1/*
2 * Copyright (c) 2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1.  Redistributions of source code must retain the above copyright
11 *     notice, this list of conditions and the following disclaimer.
12 * 2.  Redistributions in binary form must reproduce the above copyright
13 *     notice, this list of conditions and the following disclaimer in the
14 *     documentation and/or other materials provided with the distribution.
15 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of its
16 *     contributors may be used to endorse or promote products derived from
17 *     this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Portions of this software have been released under the following terms:
31 *
32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC.
33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY
34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION
35 *
36 * To anyone who acknowledges that this file is provided "AS IS"
37 * without any express or implied warranty:
38 * permission to use, copy, modify, and distribute this file for any
39 * purpose is hereby granted without fee, provided that the above
40 * copyright notices and this notice appears in all source code copies,
41 * and that none of the names of Open Software Foundation, Inc., Hewlett-
42 * Packard Company or Digital Equipment Corporation be used
43 * in advertising or publicity pertaining to distribution of the software
44 * without specific, written prior permission.  Neither Open Software
45 * Foundation, Inc., Hewlett-Packard Company nor Digital
46 * Equipment Corporation makes any representations about the suitability
47 * of this software for any purpose.
48 *
49 * Copyright (c) 2007, Novell, Inc. All rights reserved.
50 * Redistribution and use in source and binary forms, with or without
51 * modification, are permitted provided that the following conditions
52 * are met:
53 *
54 * 1.  Redistributions of source code must retain the above copyright
55 *     notice, this list of conditions and the following disclaimer.
56 * 2.  Redistributions in binary form must reproduce the above copyright
57 *     notice, this list of conditions and the following disclaimer in the
58 *     documentation and/or other materials provided with the distribution.
59 * 3.  Neither the name of Novell Inc. nor the names of its contributors
60 *     may be used to endorse or promote products derived from this
61 *     this software without specific prior written permission.
62 *
63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
73 *
74 * @APPLE_LICENSE_HEADER_END@
75 */
76
77/*
78**
79**  NAME
80**
81**      cnrcvr.c
82**
83**  FACILITY:
84**
85**      Remote Procedure Call (RPC)
86**
87**  ABSTRACT:
88**
89**  The NCA Connection Protocol Service's Receiver Service.
90**
91**
92*/
93
94#include <commonp.h>    /* Common declarations for all RPC runtime */
95#include <com.h>        /* Common communications services */
96#include <ndrp.h>       /* System (machine architecture) dependent definitions */
97#include <cnp.h>        /* NCA Connection private declarations */
98#include <cnnet.h>      /* NCA Connection network service */
99#include <cnsm.h>       /* NCA Connection state machine service */
100#include <cnassm.h>     /* NCA Connection association state machine */
101#include <cnclsm.h>     /* NCA Connection call state machine */
102#include <cnpkt.h>      /* NCA Connection packet encoding */
103#include <cnfbuf.h>     /* NCA Connection fragment buffer service */
104#include <cnassoc.h>    /* NCA Connection association service */
105#include <cnrcvr.h>     /* NCA Connection receiver service */
106#include <comauth.h>    /* Externals for Auth. Services sub-component */
107#include <cncall.h>     /* NCA connection call service */
108#include <comcthd.h>    /* Externals for call thread services component */
109#include <cncthd.h>     /* NCA Connection call executor service */
110
111/******************************************************************************/
112/*
113 * Internal variables
114 */
115/******************************************************************************/
116/*
117 * P A C K E T _ I N F O _ T A B L E
118 *
119 * Call and Association packet event information table.
120 * This table is indexed by packet type.
121 */
122
123typedef struct
124{
125    unsigned8 class;
126    unsigned8 event;
127} rpc_cn_pkt_info_t, *rpc_cn_pkt_info_p_t;
128
129#define CALL_CLASS_PKT  0       /* packet is a call related packet */
130#define ASSOC_CLASS_PKT 1       /* packet is an association related packet */
131#define DGRAM_CLASS_PKT 2       /* packet is a datagram related packet (illegal) */
132
133#ifndef RPC_C_DGRAM_TYPE_PKT
134#define RPC_C_DGRAM_TYPE_PKT 0xff     /* this is an arbitrary value */
135#endif
136
137INTERNAL rpc_cn_pkt_info_t packet_info_table[] =
138{
139    { CALL_CLASS_PKT,  RPC_C_CALL_RPC_IND },            /* 00 - request */
140    { DGRAM_CLASS_PKT, RPC_C_DGRAM_TYPE_PKT },          /* 01 - ping */
141    { CALL_CLASS_PKT,  RPC_C_CALL_RPC_CONF },           /* 02 - response */
142    { CALL_CLASS_PKT,  RPC_C_CALL_FAULT },              /* 03 - fault */
143    { DGRAM_CLASS_PKT, RPC_C_DGRAM_TYPE_PKT },          /* 04 - working */
144    { DGRAM_CLASS_PKT, RPC_C_DGRAM_TYPE_PKT },          /* 05 - nocall */
145    { DGRAM_CLASS_PKT, RPC_C_DGRAM_TYPE_PKT },          /* 06 - reject */
146    { DGRAM_CLASS_PKT, RPC_C_DGRAM_TYPE_PKT },          /* 07 - ack */
147    { DGRAM_CLASS_PKT, RPC_C_DGRAM_TYPE_PKT },          /* 08 - quit */
148    { DGRAM_CLASS_PKT, RPC_C_DGRAM_TYPE_PKT },          /* 09 - fack */
149    { DGRAM_CLASS_PKT, RPC_C_DGRAM_TYPE_PKT },          /* 10 - quack */
150    { ASSOC_CLASS_PKT, RPC_C_ASSOC_IND },               /* 11 - bind */
151    { ASSOC_CLASS_PKT, RPC_C_ASSOC_ACCEPT_CONF },       /* 12 - bind ack */
152    { ASSOC_CLASS_PKT, RPC_C_ASSOC_REJECT_CONF },       /* 13 - bind nak */
153    { ASSOC_CLASS_PKT, RPC_C_ASSOC_ALTER_CONTEXT_IND }, /* 14 - alter context */
154    { ASSOC_CLASS_PKT, RPC_C_ASSOC_ALTER_CONTEXT_CONF },/* 15 - alter context response */
155    { ASSOC_CLASS_PKT, RPC_C_ASSOC_AUTH3_IND },         /* 16 - auth3 */
156    { ASSOC_CLASS_PKT, RPC_C_ASSOC_SHUTDOWN_IND },      /* 17 - shutdown */
157    { CALL_CLASS_PKT,  RPC_C_CALL_REMOTE_ALERT_IND },   /* 18 - remote alert */
158    { CALL_CLASS_PKT,  RPC_C_CALL_ORPHANED }            /* 19 - orphaned */
159};
160
161
162/******************************************************************************/
163/*
164 * Internal routine declarations
165 */
166/******************************************************************************/
167/*
168 * R E C E I V E _ D I S P A T C H
169 */
170INTERNAL void receive_dispatch (
171        rpc_cn_assoc_p_t        /*assoc*/
172    );
173
174/*
175 * R E C E I V E _ P A C K E T
176 */
177INTERNAL void receive_packet (
178        rpc_cn_assoc_p_t        /*assoc*/,
179        rpc_cn_fragbuf_p_t      * /*fragbuf_p*/,
180        rpc_cn_fragbuf_p_t      * /*ovf_fragbuf_p*/,
181        unsigned32              * /*st*/
182    );
183
184/*
185 * R P C _ C N _ S E N D _ F A U L T
186 *
187 * This macro will cause a fault PDU to be sent back to the client
188 * and will terminate the RPC.
189 */
190#define RPC_CN_SEND_FAULT(call_r, st) \
191{\
192    rpc_binding_rep_t   *binding_r; \
193\
194    rpc__cn_call_reject ((rpc_call_rep_p_t) call_r, st);\
195    binding_r = (rpc_binding_rep_t *) (call_r)->binding_rep; \
196    RPC_CN_UNLOCK (); \
197    rpc__cn_call_end ((rpc_call_rep_p_t *) &(call_r), &st); \
198    RPC_CN_LOCK (); \
199    RPC_BINDING_RELEASE (&binding_r, \
200                         &st); \
201}
202
203
204/*
205**++
206**  ROUTINE NAME:       rpc__cn_network_receiver
207**
208**  SCOPE:              PRIVATE - declared in cnrcvr.h
209**
210**  DESCRIPTION:
211**
212**  This routine constitutes the top-level receiver thread (both client and
213**  server) and is invoked by "thread create" in "association
214**  lookaside alloc" routine to process incoming packets.
215**
216**  It receives packets on an association until terminated by a
217**  cancel, the connection breaks or a resource exhaustion problem
218**  is hit.
219**
220**  INPUTS:
221**
222**      assoc             pointer to an association control block
223**
224**  INPUTS/OUTPUTS:     none
225**
226**  OUTPUTS:            none
227**
228**  IMPLICIT INPUTS:    none
229**
230**  IMPLICIT OUTPUTS:   none
231**
232**  FUNCTION VALUE:     none
233**
234**  SIDE EFFECTS:       Posts events to the association and call state machines.
235**
236**--
237*/
238
239PRIVATE void rpc__cn_network_receiver
240(
241  rpc_cn_assoc_p_t        assoc
242)
243{
244    rpc_socket_error_t  serr;
245    volatile boolean    done = false;
246
247    //DO_NOT_CLOBBER(done);
248
249    RPC_CN_DBG_RTN_PRINTF (rpc__cn_network_receiver);
250
251    RPC_DBG_PRINTF (rpc_e_dbg_threads, RPC_C_CN_DBG_THREADS,
252        ("####### assoc->%p Entered receiver thread \n", assoc));
253
254    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
255                    ("CN: assoc->%p call_rep->none Receiver thread starting...\n",
256                     assoc));
257
258    /*
259     * Loop until a cancel is sent to this thread.
260     */
261    while (!done && !assoc->cn_ctlblk.exit_rcvr)
262    {
263        RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
264                        ("CN: assoc->%p call_rep->none Entering receive loop...\n",
265                         assoc));
266
267        /*
268         * Lock the global connection mutex to prevent other threads
269         * from running while the receiver thread is. This mutex will be
270         * released when we block (either explicitly or implicitly by a
271         * condition variable wait).
272         */
273        /* XXX is there any advantage to using a per-association mutex? */
274        RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
275                        ("CN: Attemping to lock global mutex\n"));
276        RPC_CN_LOCK ();
277        RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
278                        ("CN: Global mutex locked\n"));
279
280        /*
281         * Wait for a session/transport connection to be established.
282         */
283        DCETHREAD_TRY
284        {
285            while (assoc->cn_ctlblk.cn_state != RPC_C_CN_OPEN)
286            {
287		/*
288		 * XXX this check is to mask a race condition where the
289		 * assoc appears to be freed under us. Of course, we are
290		 * in this test relying on the fact that it is zeroed
291		 * upon deallocation and the memory isn't overwritten
292		 * which is completely bogus.
293		 *
294		 * Not sure why this is happening as rpc__cn_assoc_acb_free()
295		 * should be waiting to join this thread.
296		 */
297                if (assoc->cn_ctlblk.cn_rcvr_thread_id == (dcethread*)0)
298                {
299                    done = true;
300                    break;
301                }
302                assoc->cn_ctlblk.cn_rcvr_waiters++;
303                RPC_DBG_PRINTF (rpc_e_dbg_threads, RPC_C_CN_DBG_THREADS,
304                    ("####### assoc->%p Waiting for new connection \n", assoc));
305                DCETHREAD_TRY
306                {
307                    RPC_COND_WAIT (assoc->cn_ctlblk.cn_rcvr_cond,
308                                   rpc_g_global_mutex);
309                }
310                DCETHREAD_CATCH(dcethread_interrupt_e)
311                {
312                    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
313                                    ("CN: assoc->%p rcvr free'ed by acb_free\n",
314                                     assoc));
315                    done = true;
316                }
317                DCETHREAD_CATCH_ALL(THIS_CATCH)
318                {
319                    /*
320                     * rpc_m_unexpected_exc
321                     * "(%s) Unexpected exception was raised"
322                     */
323                    rpc_dce_svc_printf (
324                        __FILE__, __LINE__,
325                        "%s",
326                        rpc_svc_recv,
327                        svc_c_sev_fatal | svc_c_action_abort,
328                        rpc_m_unexpected_exc,
329                        "rpc__cn_network_receiver" );
330                }
331                DCETHREAD_ENDTRY
332
333                assoc->cn_ctlblk.cn_rcvr_waiters--;
334
335                if (done == true)
336                    break;
337                RPC_DBG_PRINTF (rpc_e_dbg_threads, RPC_C_CN_DBG_THREADS,
338                    ("####### assoc->%p Got a new connection \n", assoc));
339            }
340
341            if (done)
342            {
343                RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
344                                ("CN: assoc->%p call_rep->none Receiver awake ... free'ed\n",
345                                 assoc));
346            }
347            else
348            {
349                RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
350                                ("CN: assoc->%p call_rep->none Receiver awake ... Connection established\n",
351                                 assoc));
352
353                /*
354                 * Increment the association control block's reference count since we
355                 * are now using it and receive packets as long as the
356                 * connection is open.
357                 */
358                RPC_CN_ASSOC_ACB_INC_REF (assoc);
359
360                /*
361                 * A connection has been established.
362                 */
363                RPC_CN_STATS_INCR (connections);
364                rpc__server_incr_clients ();
365                DCETHREAD_TRY
366                {
367                    receive_dispatch (assoc);
368                }
369                DCETHREAD_CATCH(dcethread_interrupt_e)
370                {
371                    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
372("CN: call_rep->%p assoc->%p desc->%p receiver canceled, caught in rpc__cn_network_receiver()\n",
373                                    assoc->call_rep,
374                                    assoc,
375                                    assoc->cn_ctlblk.cn_sock));
376                }
377                DCETHREAD_CATCH_ALL(THIS_CATCH)
378                {
379                    /*
380                     * rpc_m_unexpected_exc
381                     * "(%s) Unexpected exception was raised"
382                     */
383                   rpc_dce_svc_printf (
384                       __FILE__, __LINE__,
385                       "%s",
386                       rpc_svc_recv,
387                       svc_c_sev_fatal | svc_c_action_abort,
388                       rpc_m_unexpected_exc,
389                       "rpc__cn_network_receiver" );
390                }
391                DCETHREAD_ENDTRY
392
393                RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
394                                        ("CN: assoc->%p call_rep->none No longer receiving...Close socket\n",
395                                         assoc));
396                /*
397                 * Either the connection was broken or another
398                 * thread has sent us a cancel indicating the
399                 * connection should be broken. In either case
400                 * close the socket and set the connection state
401                 * to closed.
402                 */
403                rpc__server_decr_clients();
404                RPC_CN_STATS_INCR (closed_connections);
405                serr = RPC_SOCKET_CLOSE (assoc->cn_ctlblk.cn_sock); /* must not be a cancellation point */
406                if (RPC_SOCKET_IS_ERR(serr))
407                {
408                    /*
409                     * The socket close failed.
410                     */
411                    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_ERRORS,
412("(rpc__cn_network_receiver) assoc->%p desc->%p RPC_SOCKET_CLOSE failed, error = %d\n",
413                                     assoc,
414                                     assoc->cn_ctlblk.cn_sock,
415                                     RPC_SOCKET_ETOI(serr)));
416                }
417
418                assoc->cn_ctlblk.cn_state = RPC_C_CN_CLOSED;
419
420                /*
421                 * Remove any pending cancel on this assoc. Otherwise, it's
422                 * possible that the receiver thread will see this cancel after
423                 * the next call begins.
424                 */
425                DCETHREAD_TRY
426                {
427                    dcethread_checkinterrupt();
428                }
429                DCETHREAD_CATCH_ALL(THIS_CATCH)
430                {
431                    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
432                        ("CN: assoc->%p rcvr cancel found at acb_dealloc\n",
433                        assoc));
434                }
435                DCETHREAD_ENDTRY
436
437                /*
438                 * Deallocate the association control block.
439                 */
440                rpc__cn_assoc_acb_dealloc (assoc);
441
442                /*
443                 * Check if rpc__cn_assoc_acb_free() posted the cancel.
444                 */
445                DCETHREAD_TRY
446                {
447                    dcethread_checkinterrupt();
448                }
449                DCETHREAD_CATCH(dcethread_interrupt_e)
450                {
451                    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
452                        ("CN: assoc->%p rcvr free'ed by acb_dealloc\n",
453                        assoc));
454                    done = true;
455                }
456                DCETHREAD_CATCH_ALL(THIS_CATCH)
457                {
458                    /*
459                     * rpc_m_unexpected_exc
460                     * "(%s) Unexpected exception was raised"
461                     */
462                    rpc_dce_svc_printf (
463                        __FILE__, __LINE__,
464                        "%s",
465                        rpc_svc_recv,
466                        svc_c_sev_fatal | svc_c_action_abort,
467                        rpc_m_unexpected_exc,
468                        "rpc__cn_network_receiver" );
469                }
470                DCETHREAD_ENDTRY
471            }
472        }
473        DCETHREAD_CATCH(dcethread_interrupt_e)
474        {
475            /*
476             * rpc_m_unexpected_exc
477             * "(%s) Unexpected exception was raised"
478             */
479            rpc_dce_svc_printf (
480                __FILE__, __LINE__,
481                "%s",
482                rpc_svc_recv,
483                svc_c_sev_fatal | svc_c_action_abort,
484                rpc_m_unexpected_exc,
485                "rpc__cn_network_receiver" );
486        }
487        DCETHREAD_CATCH_ALL(THIS_CATCH)
488        {
489        }
490        DCETHREAD_ENDTRY
491
492        /*
493         * Unlock the global connection mutex.
494         */
495        DCETHREAD_TRY
496        {
497            RPC_CN_UNLOCK ();
498        }
499        DCETHREAD_CATCH_ALL(THIS_CATCH)
500        {
501            /*
502             * rpc_m_unexpected_exc
503             * "(%s) Unexpected exception was raised"
504             */
505            rpc_dce_svc_printf (
506                __FILE__, __LINE__,
507                "%s",
508                rpc_svc_recv,
509                svc_c_sev_fatal | svc_c_action_abort,
510                rpc_m_unexpected_exc,
511                "rpc__cn_network_receiver" );
512        }
513        DCETHREAD_ENDTRY
514    } /* end while (!done && !assoc->cn_ctlblk.exit_rcvr) */
515
516    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
517                    ("CN: assoc->%p call_rep->none Receiver thread exiting...\n",
518                     assoc));
519}
520
521
522/******************************************************************************/
523/*
524**++
525**
526**  ROUTINE NAME:       receive_dispatch
527**
528**  SCOPE:              INTERNAL - declared locally
529**
530**  DESCRIPTION:
531**
532**  This is the low-level routine for receiving and dispatching packets.
533**
534**  This routine is called once per "connection" and will continue to
535**  receive and dispatch packets until some kind of error is encountered.
536**
537**  INPUTS:
538**
539**      assoc           pointer to an association control block
540**
541**  INPUTS/OUTPUTS:     none
542**
543**  OUTPUTS:            none
544**
545**  IMPLICIT INPUTS:    none
546**
547**  IMPLICIT OUTPUTS:   none
548**
549**  FUNCTION VALUE:     none
550**
551**  SIDE EFFECTS:       none
552**
553**--
554**/
555
556INTERNAL void receive_dispatch
557(
558  rpc_cn_assoc_p_t        assoc
559)
560{
561    rpc_cn_fragbuf_p_t          fragbuf_p;
562    rpc_cn_fragbuf_p_t          ovf_fragbuf_p;
563    rpc_cn_call_rep_p_t         call_r;
564    unsigned32                  st;
565    rpc_cn_packet_p_t           pktp;
566    unsigned8                   ptype;
567    volatile boolean                     unpack_ints = false;
568    volatile unsigned32                  i;
569    rpc_cn_syntax_t             *pres_context;
570    unsigned32                  auth_st;
571    rpc_cn_sec_context_t        *sec_context;
572    boolean                     already_unpacked;
573
574    //DO_NOT_CLOBBER(unpack_ints);
575    //DO_NOT_CLOBBER(i);
576
577    /*
578     * Onetime (auto) initialization.
579     */
580    st = rpc_s_ok;
581    fragbuf_p = NULL;
582    ovf_fragbuf_p = NULL;
583    call_r = NULL;
584    sec_context = NULL;
585
586    /*
587     * Main receive processing.
588     *
589     * We loop, receiving and processing packets until some kind of error
590     * is encountered.
591     */
592    for (i = 0;; i++)
593    {
594        RPC_LOG_CN_PROCESS_PKT_NTR;
595
596        /*
597         * Increment the per-association security context next receive
598         * sequence number.
599         */
600        assoc->security.assoc_next_rcv_seq = i;
601
602        /*
603         * Receive a packet from the network.
604         */
605        DCETHREAD_TRY
606        {
607            receive_packet (assoc, &fragbuf_p, &ovf_fragbuf_p, &st);
608        }
609        DCETHREAD_CATCH(dcethread_interrupt_e)
610        {
611            RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
612                            ("CN: call_rep->%p assoc->%p desc->%p receiver canceled, caught in receive_dispatch()\n",
613                            assoc->call_rep,
614                            assoc,
615                            assoc->cn_ctlblk.cn_sock));
616           st = rpc_s_connection_closed;
617        }
618        DCETHREAD_CATCH_ALL(THIS_CATCH)
619        {
620            /*
621             * rpc_m_unexpected_exc
622             * "(%s) Unexpected exception was raised"
623             */
624            rpc_dce_svc_printf (
625                __FILE__, __LINE__,
626                "%s",
627                rpc_svc_recv,
628                svc_c_sev_fatal | svc_c_action_abort,
629                rpc_m_unexpected_exc,
630                "receive_dispatch" );
631        }
632        DCETHREAD_ENDTRY
633
634        if (st != rpc_s_ok)
635        {
636            break;
637        }
638
639        already_unpacked = false;
640
641        /*
642         * Point to the packet header.
643         */
644        assert(fragbuf_p != NULL);
645        pktp = (rpc_cn_packet_p_t) fragbuf_p->data_p;
646
647        /*
648         * Trace the incoming packet.
649         */
650        RPC_CN_PKT_TRC (pktp);
651        RPC_CN_PKT_DUMP (pktp, fragbuf_p->data_size);
652
653        /*
654         * Keep some stats on the packets received.
655         */
656        RPC_CN_STATS_INCR (pstats[RPC_CN_PKT_PTYPE (pktp)].rcvd);
657        RPC_CN_STATS_INCR (pkts_rcvd);
658
659        /*
660         * Setup some local variables.
661         */
662        ptype = RPC_CN_PKT_PTYPE (pktp);
663
664	/*
665	 * Make sure that we have a valid packet type.
666	 * If not, we return an error, and the caller will close
667	 * the connection.
668	 */
669        if (/* (ptype < 0) ||*/ (ptype > RPC_C_CN_PKT_MAX_TYPE) ||
670            (packet_info_table[ptype].class == DGRAM_CLASS_PKT))
671        {
672            st = rpc_s_protocol_error;
673            break;
674        }
675
676        /*
677         * Do some first packet only processing...
678         */
679        if (i == 0)
680        {
681            /*
682             * Stash the remote NDR format away. Also create boolean
683             * to determine whether we have to bother unpacking the
684             * packet header.
685             */
686            NDR_UNPACK_DREP (&(RPC_CN_ASSOC_NDR_FORMAT (assoc)),
687                             RPC_CN_PKT_DREP (pktp));
688            if ((NDR_DREP_INT_REP (RPC_CN_PKT_DREP (pktp)) !=
689                 NDR_LOCAL_INT_REP))
690            {
691                unpack_ints = true;
692            }
693            else
694            {
695                unpack_ints = false;
696            }
697        }
698        else
699        {
700            /*
701             * Sanity check the major and minor version numbers.
702             * We let the association state machine do this check
703             * in the case BIND packets because the
704             * protocol calls for a call reject if the versions
705             * do not match at that point.
706             * For subsequent packets, we do the check here.
707             */
708            if (!(ptype == RPC_C_CN_PKT_BIND) &&
709                ((RPC_CN_PKT_VERS (pktp) != RPC_C_CN_PROTO_VERS) ||
710                (RPC_CN_PKT_VERS_MINOR (pktp) > RPC_C_CN_PROTO_VERS_MINOR)))
711            {
712                st = rpc_s_rpc_prot_version_mismatch;
713                break;
714            }
715        }
716
717        auth_st = rpc_s_ok;
718
719        /*
720         * Determine whether the received PDU contains an
721         * authentication trailer.  We don't care about byte
722         * ordering in the following macro invocation because
723         * the trailer length is compared with zero to determine
724         * whether or not the trailer is present.
725         */
726        if (RPC_CN_PKT_AUTH_TLR_PRESENT (pktp))
727        {
728            rpc_cn_auth_tlr_t               *auth_tlr;
729            unsigned16                      auth_len;
730            unsigned32                      key_id;
731            unsigned16                      frag_len;
732
733            /*
734             * If the pdu is a bind or alter-context pdu and we need to
735             * unpack the packet, save the raw form of the pdu so that
736             * the checksum can be computed correctly later.  Do this by
737             * allocating a fragbuf and chaining it to the association
738             * control block, then copying the packet to it.  The fragbuf
739             * will be deallocated in the state machine after invoking
740             * recv_check.
741             */
742            if ((unpack_ints) &&
743                ((ptype == RPC_C_CN_PKT_BIND) ||
744                 (ptype == RPC_C_CN_PKT_BIND_ACK) ||
745                 (ptype == RPC_C_CN_PKT_ALTER_CONTEXT) ||
746                 (ptype == RPC_C_CN_PKT_ALTER_CONTEXT_RESP) ||
747                 (ptype == RPC_C_CN_PKT_BIND_NAK) ||
748                 (ptype == RPC_C_CN_PKT_AUTH3)))
749            {
750                assoc->raw_packet_p = rpc__cn_fragbuf_alloc (true);
751                assoc->raw_packet_p->data_size = fragbuf_p->data_size;
752                memcpy (assoc->raw_packet_p->data_p,
753                        fragbuf_p->data_p,
754                        fragbuf_p->data_size);
755            }
756
757            /*
758             * Locate the authentication trailer in the PDU.
759             */
760            auth_len = RPC_CN_PKT_AUTH_LEN (pktp);
761            if (unpack_ints)
762            {
763                /* no need to check end_of_pkt since its a copy of pkt data */
764                SWAB_INPLACE_16 (auth_len);
765            }
766
767            auth_tlr = (rpc_cn_auth_tlr_t *) ((unsigned8 *)(pktp) +
768                fragbuf_p->data_size -
769                (auth_len + RPC_CN_PKT_SIZEOF_COM_AUTH_TLR));
770            if ( ((unsigned8 *)(auth_tlr) < (unsigned8 *)(pktp)) ||
771                ((unsigned8 *)(auth_tlr) > (unsigned8 *)(pktp) + fragbuf_p->data_size) ||
772                ((unsigned8 *)(auth_tlr) + auth_len < (unsigned8 *)(pktp)) ||
773                ((unsigned8 *)(auth_tlr) + auth_len > (unsigned8 *)(pktp) + fragbuf_p->data_size) )
774            {
775                RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
776                                ("CN: call_rep->%p assoc->%p desc->%p invalid auth_tlr\n",
777                                 assoc->call_rep,
778                                 assoc,
779                                 assoc->cn_ctlblk.cn_sock));
780                st = rpc_s_protocol_error;
781                break;
782            }
783
784            /*
785             * Find the appropriate security context element using the key ID
786             * contained in the auth_value part of the trailer.  Also obtain
787             * the size of the credentials in the proper format.
788             */
789            key_id = auth_tlr->key_id;
790            if (unpack_ints)
791            {
792                /* no need to check end_of_pkt since its a copy of pkt data */
793                SWAB_INPLACE_32 (key_id);
794            }
795
796            if ((ptype != RPC_C_CN_PKT_BIND) &&
797                (ptype != RPC_C_CN_PKT_ALTER_CONTEXT) &&
798                (ptype != RPC_C_CN_PKT_BIND_ACK) &&
799                (ptype != RPC_C_CN_PKT_ALTER_CONTEXT_RESP))
800            {
801                rpc_authn_protocol_id_t authn_protocol = rpc_c_authn_none;
802
803                rpc__cn_assoc_sec_lkup_by_id (assoc,
804                                              key_id,
805                                              &sec_context,
806                                              &auth_st);
807
808                if (auth_st == rpc_s_ok)
809                {
810                    authn_protocol = RPC_CN_AUTH_CVT_ID_WIRE_TO_API (auth_tlr->auth_type, &auth_st);
811                }
812
813                /*
814                 * If a security context was located apply the
815                 * per-packet security check. Any errors found in either
816                 * locating the security context or during the check will
817                 * be handled below according to the type of PDU received.
818                 */
819                if (auth_st == rpc_s_ok)
820                {
821
822                    /*
823                     * Note that cred_len is zero for all per-message
824                     * packets.
825                     */
826                    RPC_CN_AUTH_RECV_CHECK (authn_protocol,
827                                            &assoc->security,
828                                            sec_context,
829                                            (rpc_cn_common_hdr_t *)pktp,
830                                            fragbuf_p->data_size,
831                                            0, /* cred_len */
832                                            auth_tlr,
833                                            unpack_ints,
834                                            &auth_st);
835                    if (auth_st == rpc_s_ok)
836                    {
837                        /*
838                         * Unpack the header part of the packet.
839                         * This will make it easier to remove from the frag
840                         * length any padding that was required to
841                         * get the auth trailer 4-byte aligned at
842                         * the sender.
843                         *
844                         * Since recv_check may have moved the auth_tlr,
845                         * we get the pointer again.
846                         */
847                        if (unpack_ints)
848                        {
849                            st = rpc__cn_unpack_hdr (pktp, fragbuf_p->data_size);
850                            if (st != rpc_s_ok)
851                            {
852                                RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
853                                                ("CN: call_rep->%p assoc->%p desc->%p auth rpc__cn_unpack_hdr failed\n",
854                                                 assoc->call_rep,
855                                                 assoc,
856                                                 assoc->cn_ctlblk.cn_sock));
857                                break;
858                            }
859                            already_unpacked = true;
860                        }
861                        auth_len = RPC_CN_PKT_AUTH_LEN (pktp);
862                        auth_tlr = (rpc_cn_auth_tlr_t *) ((unsigned8 *)(pktp) +
863                                                          fragbuf_p->data_size -
864                                                          (auth_len
865                                                           +
866                                                           RPC_CN_PKT_SIZEOF_COM_AUTH_TLR));
867                        if ( ((unsigned8 *)(auth_tlr) < (unsigned8 *)(pktp)) ||
868                            ((unsigned8 *)(auth_tlr) > (unsigned8 *)(pktp) + fragbuf_p->data_size) ||
869                            ((unsigned8 *)(auth_tlr) + auth_len < (unsigned8 *)(pktp)) ||
870                            ((unsigned8 *)(auth_tlr) + auth_len > (unsigned8 *)(pktp) + fragbuf_p->data_size) )
871                        {
872                            RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
873                                            ("CN: call_rep->%p assoc->%p desc->%p invalid auth_tlr in sec context\n",
874                                             assoc->call_rep,
875                                             assoc,
876                                             assoc->cn_ctlblk.cn_sock));
877                            st = rpc_s_protocol_error;
878                            break;
879                        }
880
881                        frag_len = RPC_CN_PKT_FRAG_LEN (pktp);
882                        if ( (frag_len > fragbuf_p->data_size) || (frag_len < auth_tlr->stub_pad_length) )
883                        {
884                            RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
885                                            ("CN: call_rep->%p assoc->%p desc->%p invalid frag_len\n",
886                                             assoc->call_rep,
887                                             assoc,
888                                             assoc->cn_ctlblk.cn_sock));
889                            st = rpc_s_protocol_error;
890                            break;
891                        }
892
893                        frag_len -= auth_tlr->stub_pad_length;
894                        RPC_CN_PKT_FRAG_LEN (pktp) = frag_len;
895
896                        if (fragbuf_p->data_size < auth_tlr->stub_pad_length)
897                        {
898                            RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
899                                            ("CN: call_rep->%p assoc->%p desc->%p invalid stub_pad_length\n",
900                                             assoc->call_rep,
901                                             assoc,
902                                             assoc->cn_ctlblk.cn_sock));
903                            st = rpc_s_protocol_error;
904                            break;
905                        }
906                        fragbuf_p->data_size -= auth_tlr->stub_pad_length;
907                    }
908                    else
909                    {
910                        /*
911                         * Handle any error which occured while performing
912                         * either the recv check or key ID lookup. Errors which
913                         * occur on the server for a call class PDU will be
914                         * handled later by sending a fault PDU back.
915                         *
916                         * On the client side this error should just be
917                         * handed back to the client thread waiting, if
918                         * any.
919                         *
920                         * On the server side the error should be reflected
921                         * back to the client on either a FAULT
922                         * PDU if the recv_check failed on a call class
923                         * PDU. If it failed on an assoc class PDU then the
924                         * best we can probably do is close the association
925                         * (it may be possible to respond with a BIND_NAK
926                         * if the recv_check failed on a BIND).
927                         */
928                        if (assoc->assoc_flags & RPC_C_CN_ASSOC_CLIENT)
929                        {
930                            (*fragbuf_p->fragbuf_dealloc)(fragbuf_p);
931                            assert(sec_context != NULL);
932                            sec_context->sec_status = auth_st;
933                            RPC_CN_ASSOC_WAKEUP (assoc);
934                            continue;
935                        }
936                        else
937                        {
938                            dce_error_string_t error_text;
939                            int temp_status;
940
941                            dce_error_inq_text(auth_st, error_text, &temp_status);
942                            /*
943                             * rpc_m_call_failed_s
944                             * "%s on server failed: %s"
945                             */
946                            rpc_dce_svc_printf (
947                                __FILE__, __LINE__,
948                                "%s %x",
949                                rpc_svc_recv,
950                                svc_c_sev_error,
951                                rpc_m_call_failed_s,
952                                "RPC_CN_AUTH_RECV_CHECK",
953                                error_text );
954
955                            if (packet_info_table[ptype].class == ASSOC_CLASS_PKT)
956                            {
957                                break;
958                            }
959                        }
960                    }
961                }
962            }
963        }
964        else
965        {
966            if ((assoc->assoc_flags & RPC_C_CN_ASSOC_CLIENT) &&
967               (ptype == RPC_C_CN_PKT_RESPONSE) &&
968               (RPC_CN_PKT_AUTH_REQUIRED(assoc->call_rep->binding_rep->auth_info)))
969            {
970                RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
971                        ("CN: auth_info %p\n", assoc->call_rep->binding_rep->auth_info));
972                RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
973                        ("CN: should not continue further with this PDU\n"));
974                (*fragbuf_p->fragbuf_dealloc)(fragbuf_p);
975                st = rpc_s_authn_level_mismatch;
976                RPC_CN_ASSOC_WAKEUP (assoc);
977                break;
978            }
979        }
980
981        /*
982         * Unpack the packet header, if necessary, and check to see
983         * if the packet type is within the legal range of values.
984         */
985        if (unpack_ints && !already_unpacked)
986        {
987            st = rpc__cn_unpack_hdr (pktp, fragbuf_p->data_size);
988            if (st != rpc_s_ok)
989            {
990                RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
991                                ("CN: call_rep->%p assoc->%p desc->%p rpc__cn_unpack_hdr failed\n",
992                                 assoc->call_rep,
993                                 assoc,
994                                 assoc->cn_ctlblk.cn_sock));
995                st = rpc_s_connection_closed;
996                break;
997            }
998        }
999
1000        /*
1001         * Finally, post the event to the appropriate state machine
1002         */
1003        if (packet_info_table[ptype].class == CALL_CLASS_PKT)
1004        {
1005            if (assoc->assoc_flags & RPC_C_CN_ASSOC_CLIENT &&
1006                assoc->alter_call_id >= 0 &&
1007                assoc->alter_call_id == RPC_CN_PKT_CALL_ID (pktp))
1008            {
1009                /* We got a call-level response to a network-level request.
1010                   Neither the association state machine nor the call
1011                   state machine are prepared to handle this.  Abort the
1012                   association */
1013                RPC_CN_ASSOC_EVAL_NETWORK_EVENT (assoc,
1014                                                 RPC_C_ASSOC_ABORT_REQ,
1015                                                 fragbuf_p,
1016                                                 st);
1017            }
1018            else if ((ptype == RPC_C_CN_PKT_REQUEST)
1019                &&
1020                (RPC_CN_PKT_FLAGS (pktp) & RPC_C_CN_FLAGS_FIRST_FRAG))
1021            {
1022                /*
1023                 * This is the first fragment of a call request packet.
1024                 * Allocate a call rep and mark it as being a server
1025                 * call rep.
1026                 */
1027                call_r = (rpc_cn_call_rep_t *)
1028                    rpc__list_element_alloc (&rpc_g_cn_call_lookaside_list,
1029                                             true);
1030                if (call_r == NULL)
1031                {
1032                    st = rpc_s_no_memory;
1033                    break;
1034                }
1035                call_r->common.is_server = true;
1036
1037                /*
1038                 * Place the new call rep in the association for
1039                 * use in cancel processing.
1040                 */
1041                rpc__cn_assoc_push_call (assoc, call_r, &st);
1042                if (st != rpc_s_ok)
1043                {
1044                    assoc->call_rep = NULL;
1045                    rpc__list_element_free (&rpc_g_cn_call_lookaside_list,
1046                                            (dce_pointer_t) call_r);
1047                    break;
1048                }
1049
1050                /*
1051                 * Initialize the server call state machine.
1052                 */
1053                rpc__cn_sm_init (rpc_g_cn_server_call_sm,
1054                                 rpc_g_cn_server_call_action_tbl,
1055                                 &(call_r->call_state),
1056				 rpc_c_cn_svr_call);
1057
1058                call_r->num_pkts = 0;
1059                call_r->sec = sec_context;
1060                call_r->cn_call_status = rpc_s_ok;
1061                call_r->last_frag_received = false;
1062                call_r->call_executed = false;
1063                call_r->common.u.server.cthread.is_queued = false;
1064                call_r->prot_tlr = NULL;
1065
1066                {
1067                int i;
1068                for( i=1; i<RPC_C_MAX_IOVEC_LEN; i++ ) {
1069                    call_r->buffered_output.iov.elt[i].buff_addr = NULL;
1070                    call_r->buffered_output.iov.elt[i].buff_dealloc = NULL;
1071                }
1072                }
1073
1074                /*
1075                 * Initialize some cancel state information.
1076                 */
1077                call_r->common.u.server.cancel.accepting = true;
1078                call_r->common.u.server.cancel.queuing = true;
1079                call_r->common.u.server.cancel.had_pending = false;
1080                call_r->common.u.server.cancel.count = 0;
1081                call_r->u.server.cancel.local_count = 0;
1082
1083                /*
1084                 * Allocate a binding rep and put either a nil UUID
1085                 * or the object UUID in the request packet header in
1086                 * it, if present.
1087                 */
1088                if (RPC_CN_PKT_FLAGS (pktp) & RPC_C_CN_FLAGS_OBJECT_UUID)
1089                {
1090                    call_r->binding_rep =
1091                    rpc__binding_alloc (true,
1092                                        &RPC_CN_PKT_OBJECT (pktp),
1093                                        RPC_C_PROTOCOL_ID_NCACN,
1094                                        NULL,
1095                                        &st);
1096                }
1097                else
1098                {
1099                    call_r->binding_rep =
1100                    rpc__binding_alloc (true,
1101                                        &uuid_g_nil_uuid,
1102                                        RPC_C_PROTOCOL_ID_NCACN,
1103                                        NULL,
1104                                        &st);
1105                }
1106
1107                /*
1108                 * If the binding_alloc failed, simply break out of
1109                 * the loop to close the connection.
1110                 */
1111                if (st != rpc_s_ok)
1112                {
1113                    break;
1114                }
1115
1116                /*
1117                 * Put the association group id in the binding rep.
1118                 */
1119                ((rpc_cn_binding_rep_t *)call_r->binding_rep)->grp_id
1120                    = assoc->assoc_grp_id;
1121                call_r->assoc = assoc;
1122
1123		/*
1124		 * If auth protection level is rpc_c_protect_level_connect
1125		 * the request pdu does not include auth tlr and so auth_len
1126		 * field is set to zero. This disables security context lookup
1127		 * by its key_id (transferred in auth_tlr).
1128		 * In such case pass security context from association itself.
1129		 */
1130		if (!sec_context)
1131		{
1132                    sec_context = assoc->security.assoc_current_sec_context;
1133		}
1134
1135                /*
1136                 * Attach the auth info, if any, to the new binding
1137                 * rep. Make sure to add a reference to it.
1138                 */
1139                if (sec_context)
1140                {
1141                    call_r->binding_rep->auth_info = sec_context->sec_info;
1142                    RPC_CN_AUTH_ADD_REFERENCE(sec_context->sec_info);
1143                }
1144
1145                /*
1146                 * Attach transport info to the bindng rep
1147                 */
1148                call_r->binding_rep->transport_info = assoc->transport_info;
1149                rpc__transport_info_retain(assoc->transport_info);
1150
1151                /*
1152                 * Post the event to the call state machine.
1153                 */
1154                RPC_CN_POST_FIRST_CALL_SM_EVENT (call_r,
1155                                                 assoc,
1156                                                 packet_info_table[ptype].event,
1157                                                 fragbuf_p,
1158                                                 st);
1159
1160                /*
1161                 * Now that we have a call rep set up and are in the
1162                 * call_request state see whether the security PDU
1163                 * receive check or key ID lookup performed earlier in this routine,
1164                 * if required, passed. If it failed a fault PDU
1165                 * will be sent back to the client.
1166                 */
1167                if (st != rpc_s_ok)
1168                {
1169                    RPC_CN_SEND_FAULT (call_r, st);
1170                    fragbuf_p = NULL;
1171                    continue;
1172                }
1173                if (auth_st != rpc_s_ok)
1174                {
1175                    RPC_CN_SEND_FAULT (call_r, auth_st);
1176                    fragbuf_p = NULL;
1177                    continue;
1178                }
1179
1180                /*
1181                 * Get the i/f id and version using the presentation
1182                 * context id in the header.
1183                 */
1184                rpc__cn_assoc_syntax_lkup_by_id (assoc,
1185                                                 RPC_CN_PKT_PRES_CONT_ID (pktp),
1186                                                 &pres_context,
1187                                                 &st);
1188                if (st != rpc_s_ok)
1189                {
1190                    RPC_CN_SEND_FAULT (call_r, st);
1191                    fragbuf_p = NULL;
1192                    continue;
1193                }
1194
1195                call_r->u.server.if_id = &pres_context->syntax_abstract_id.id;
1196                call_r->u.server.if_vers = pres_context->syntax_abstract_id.version;
1197                call_r->transfer_syntax.index = pres_context->syntax_vector_index;
1198                call_r->transfer_syntax.convert_epv = pres_context->syntax_epv;
1199                call_r->u.server.ihint = pres_context->syntax_ihint;
1200                call_r->context_id = pres_context->syntax_pres_id;
1201
1202                /*
1203                 * Invoke a call thread.
1204                 */
1205                rpc__cthread_invoke_null ((rpc_call_rep_p_t) call_r,
1206                                          &call_r->binding_rep->obj,
1207                                          call_r->u.server.if_id,
1208                                          call_r->u.server.if_vers,
1209                                          (unsigned32) call_r->opnum,
1210                                          rpc__cn_call_executor,
1211                                          (dce_pointer_t) call_r,
1212                                          &st);
1213
1214                /*
1215                 * Check whether the call was queued. If it was, just
1216                 * set the status code to "ok".
1217                 */
1218                if (st == rpc_s_call_queued)
1219                {
1220                    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
1221                                    ("CN: call_rep->%p assoc->%p desc->%p call queued\n",
1222                                     call_r,
1223                                     assoc,
1224                                     assoc->cn_ctlblk.cn_sock));
1225                    st = rpc_s_ok;
1226                }
1227                else
1228                {
1229                    /*
1230                     * If we get an error back, then we were unable to
1231                     * create the call thread.  Send a fault PDU.
1232                     */
1233                    if (st != rpc_s_ok)
1234                    {
1235                        RPC_CN_SEND_FAULT (call_r, st);
1236                        fragbuf_p = NULL;
1237                        continue;
1238                    }
1239                }
1240
1241                /*
1242                 * Keep some stats on the number of calls received.
1243                 */
1244                RPC_CN_STATS_INCR (calls_rcvd);
1245            }
1246            else
1247            {
1248                RPC_CN_POST_CALL_SM_EVENT (assoc,
1249                                           packet_info_table[ptype].event,
1250                                           fragbuf_p,
1251                                           st);
1252            }
1253        }
1254        else
1255        {
1256            RPC_CN_ASSOC_EVAL_NETWORK_EVENT (assoc,
1257                                             packet_info_table[ptype].event,
1258                                             fragbuf_p,
1259                                             st);
1260        }
1261
1262        /*
1263         * Unlock the CN global mutex, yield the processor to allow
1264         * another thread to run and re-acquire the CN global mutex.
1265         */
1266        RPC_CN_UNLOCK ();
1267        dcethread_yield ();
1268        RPC_CN_LOCK ();
1269
1270        /*
1271         * NULL our pointer to the fragment buffer so we'll be forced to get
1272         * a new one.
1273         */
1274        fragbuf_p = NULL;
1275        RPC_LOG_CN_PROCESS_PKT_XIT;
1276    } /* end-for (i = 0;; i++) */
1277
1278    /*
1279     * Some failure occured while receiving packets. Indicate this
1280     * failure to the association state machine.
1281     */
1282    rpc__cn_assoc_post_error (assoc, st);
1283
1284    /*
1285     * If we still have a fragbufs, then deallocate them.
1286     */
1287    if (fragbuf_p)
1288    {
1289        (*fragbuf_p->fragbuf_dealloc)(fragbuf_p);
1290    }
1291    if (ovf_fragbuf_p)
1292    {
1293        (*ovf_fragbuf_p->fragbuf_dealloc)(ovf_fragbuf_p);
1294    }
1295}
1296
1297
1298/******************************************************************************/
1299/*
1300**++
1301**
1302**  ROUTINE NAME:       receive_packet
1303**
1304**  SCOPE:              INTERNAL - declared locally
1305**
1306**  DESCRIPTION:
1307**
1308**  This is a (large) wrapper around the socket recvmsg() routine.
1309**
1310**  We do this since stream sockets don't guarantee the preservation of RPC
1311**  packet boundaries.  If we receive partial packets, we have to piece them
1312**  back together again.  Also, if we receive more than one packet during a
1313**  read operation, we preserve the excess bytes read and return them the next
1314**  time we are called.
1315**
1316**  INPUTS:
1317**
1318**      assoc           pointer to an association control block
1319**
1320**  INPUTS/OUTPUTS:
1321**
1322**      fragbuf_p       pointer to a fragbuf pointer
1323**      ovf_fragbuf_p   pointer to a overflow fragbuf pointer
1324**
1325**  OUTPUTS:
1326**
1327**      st              the return status of this routine
1328**
1329**  IMPLICIT INPUTS:    none
1330**
1331**  IMPLICIT OUTPUTS:   none
1332**
1333**  FUNCTION VALUE:     none
1334**
1335**  SIDE EFFECTS:       none
1336**
1337**--
1338**/
1339
1340INTERNAL void receive_packet
1341(
1342  rpc_cn_assoc_p_t        assoc,
1343  rpc_cn_fragbuf_p_t      *fragbuf_p,
1344  rpc_cn_fragbuf_p_t      *ovf_fragbuf_p,
1345  unsigned32              *st
1346)
1347{
1348    rpc_cn_fragbuf_t    * volatile fbp;
1349    volatile unsigned16 frag_length;
1350    size_t              bytes_rcvd = 0;
1351    rpc_socket_iovec_t  iov;
1352    volatile rpc_socket_error_t  serr = 0;
1353    signed32            need_bytes;
1354    static rpc_addr_p_t addr = NULL;
1355
1356    //DO_NOT_CLOBBER(fbp);
1357    //DO_NOT_CLOBBER(frag_length);
1358
1359    RPC_LOG_CN_RCV_PKT_NTR;
1360    CODING_ERROR (st);
1361
1362    /*
1363     * One time (auto) initialization.
1364     */
1365    fbp = NULL;
1366
1367    /*
1368     * Assume the worst is going to happen and zap our return value.
1369     */
1370    *fragbuf_p = NULL;
1371
1372    /*
1373     * If we have a left over fragment buffer (overflow), then use it.
1374     */
1375    if (*ovf_fragbuf_p != NULL)
1376    {
1377        fbp = *ovf_fragbuf_p;
1378        *ovf_fragbuf_p = NULL;
1379    }
1380
1381    /*
1382     * If we need a fragment buffer, then allocate one.
1383     */
1384    if (fbp == NULL)
1385    {
1386        fbp = rpc__cn_fragbuf_alloc (true);
1387    }
1388
1389    /*
1390     ******************************************************************
1391     * At this point we must determine which of the following 3
1392     * situations we are faced with:
1393     *
1394     *  1) The fragbuf is empty.
1395     *  2) The fragbuf contains a partial RPC packet.
1396     *  3) The fragbuf contains a complete RPC packet.
1397     *
1398     * The first thing we do is to check whether or not we have
1399     * enough data in the current fragbuf to determine the complete
1400     * RPC packet length.  Note that in the 3rd case, the fragbuf may
1401     * actually contain more than one RPC packet.
1402     *
1403     ******************************************************************
1404     */
1405
1406    /*
1407     * Do we have enough data in the fragbuf to determine the RPC packet
1408     * length?
1409     *
1410     * If we do, we can figure out exactly how many bytes to request on our
1411     * next read. If we don't, we just ask for the maximum number of bytes
1412     * that our fragbuf will hold.
1413     */
1414    if (fbp->data_size >= RPC_C_CN_FRAGLEN_HEADER_BYTES)
1415    {
1416        /*
1417         * Okay, we have enough of the header to figure out how big
1418         * this fragment is.
1419         */
1420        frag_length = RPC_CN_PKT_FRAG_LEN ((rpc_cn_packet_p_t)(fbp->data_p));
1421
1422        /*
1423         * Swap bytes if our integer formats are different.
1424         */
1425        if (NDR_DREP_INT_REP(RPC_CN_PKT_DREP((rpc_cn_packet_p_t)fbp->data_p))
1426            != NDR_LOCAL_INT_REP)
1427        {
1428            SWAB_INPLACE_16 (frag_length);
1429        }
1430
1431        /*
1432         * Figure out how many bytes we need.
1433         */
1434        need_bytes = frag_length - fbp->data_size;
1435    }
1436    else
1437    {
1438        /*
1439         * We don't have enough data to compute the fragment length.
1440         */
1441        frag_length = 0;
1442
1443        /*
1444         * Ask for as many bytes as our fragbuf will hold.
1445         */
1446        need_bytes = fbp->max_data_size - fbp->data_size;
1447    }
1448
1449    /*
1450     * Read from the socket until we've read at least one entire packet.
1451     */
1452    while (need_bytes > 0)
1453    {
1454
1455        /*
1456         * Initialize our iovector.
1457         */
1458        iov.iov_base = (byte_p_t)((unsigned8 *)(fbp->data_p) + fbp->data_size);
1459        iov.iov_len = need_bytes;
1460
1461        /*
1462         * Release the CN global mutex before reading from the
1463         * socket. This will allow other threads to run if we have to
1464         * block here.
1465         */
1466        RPC_CN_UNLOCK ();
1467        DCETHREAD_TRY
1468        {
1469#ifdef NON_CANCELLABLE_IO
1470            /*
1471             * By POSIX definition dcethread_enableasync_throw is not a "cancel
1472             * point" because it must return an error status and an errno.
1473             * dcethread_enableasync_throw(1) will not deliver
1474             * a pending cancel nor will the cancel be delivered asynchronously,
1475             * thus the need for dcethread_checkinterrupt.
1476             */
1477	    dcethread_enableasync_throw(1);
1478	    dcethread_checkinterrupt();
1479#endif /* NON_CANCELLABLE_IO */
1480            serr = rpc__socket_recvmsg(
1481                assoc->cn_ctlblk.cn_sock,
1482                &iov,
1483                1,
1484                addr,
1485                &bytes_rcvd);
1486#ifdef NON_CANCELLABLE_IO
1487	    dcethread_enableasync_throw(0);
1488#endif /* NON_CANCELLABLE_IO */
1489        }
1490        DCETHREAD_CATCH (dcethread_interrupt_e)
1491        {
1492#ifdef NON_CANCELLABLE_IO
1493            dcethread_enableasync_throw(0);
1494#endif /* NON_CANCELLABLE_IO */
1495            RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
1496("CN: call_rep->%p assoc->%p desc->%p receiver canceled, caught in receive_packet()\n",
1497                             assoc->call_rep,
1498                             assoc,
1499                             assoc->cn_ctlblk.cn_sock));
1500
1501            /*
1502             * Re-acquire the CN global mutex and free any fragment
1503             * buffers we have outstanding.
1504             */
1505            RPC_CN_LOCK ();
1506            if (fbp)
1507            {
1508                (*(fbp)->fragbuf_dealloc)(fbp);
1509            }
1510            DCETHREAD_RERAISE;
1511        }
1512        DCETHREAD_CATCH_ALL(THIS_CATCH)
1513        {
1514            /*
1515             * rpc_m_unexpected_exc
1516             * "(%s) Unexpected exception was raised"
1517             */
1518            rpc_dce_svc_printf (
1519                __FILE__, __LINE__,
1520                "%s",
1521                rpc_svc_recv,
1522                svc_c_sev_fatal | svc_c_action_abort,
1523                rpc_m_unexpected_exc,
1524                "receive_packet" );
1525        }
1526        DCETHREAD_ENDTRY
1527
1528        /*
1529         * Re-acquire the CN global mutex.
1530         */
1531        RPC_CN_LOCK ();
1532
1533        /*
1534         * Hold off on processing the packet if the sending thread for this
1535         * connection is currently in a sendmsg.
1536         */
1537        while (assoc->cn_ctlblk.in_sendmsg)
1538        {
1539            RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
1540                            ("CN: call_rep->%p assoc->%p desc->%p waiting for sendmsg to complete...\n",
1541                             assoc->call_rep,
1542                             assoc,
1543                             assoc->cn_ctlblk.cn_sock));
1544            assoc->cn_ctlblk.waiting_for_sendmsg_complete = true;
1545            RPC_COND_WAIT (assoc->cn_ctlblk.cn_rcvr_cond,
1546                           rpc_g_global_mutex);
1547            RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
1548                            ("CN: call_rep->%p assoc->%p desc->%p sendmsg complete\n",
1549                             assoc->call_rep,
1550                             assoc,
1551                             assoc->cn_ctlblk.cn_sock));
1552            assoc->cn_ctlblk.waiting_for_sendmsg_complete = false;
1553        }
1554
1555        /*
1556         * Process any errors reading the socket or any errors detected by
1557         * other threads using this association. These other threads will have
1558         * cleaned up the assoc state and the receiver thread just has to close
1559         * the connection now.
1560         */
1561        if ((RPC_SOCKET_IS_ERR (serr))
1562            ||
1563            (bytes_rcvd == 0)
1564            ||
1565            (assoc->assoc_local_status != rpc_s_ok)
1566            ||
1567            (assoc->assoc_status != rpc_s_ok))
1568        {
1569            /*
1570             * Make sure the connection is really closed. It could
1571             * be a zero length sequenced packet socket packet.
1572             */
1573            if (rpc__naf_is_connect_closed (assoc->cn_ctlblk.cn_sock, st))
1574            {
1575                RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
1576                                ("CN: call_rep->%p assoc->%p desc->%p connection closed recvmsg failed serr = %x, bytes_rcvd = %ld\n",
1577                                 assoc->call_rep,
1578                                 assoc,
1579                                 assoc->cn_ctlblk.cn_sock,
1580                                 serr,
1581                                 bytes_rcvd));
1582
1583                /*
1584                 * Deallocate the fragbuf which we were using.
1585                 */
1586                (*fbp->fragbuf_dealloc)(fbp);
1587
1588                *st = rpc_s_connection_closed;
1589                return;
1590            }
1591        }
1592
1593        RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
1594                        ("CN: call_rep->%p assoc->%p desc->%p received %ld bytes\n",
1595                         assoc->call_rep,
1596                         assoc,
1597                         assoc->cn_ctlblk.cn_sock,
1598                         bytes_rcvd));
1599
1600        /*
1601         * Update the number of bytes received.
1602         */
1603        fbp->data_size += bytes_rcvd;
1604
1605        /*
1606         * If we don't already know the fragment length, then we now have to go
1607         * through the same gymnastics that we did before vis a vis determining
1608         * whether or not we've read enough of this fragment to determine the
1609         * complete fragment length.
1610         */
1611        if ((frag_length == 0) && (fbp->data_size >= RPC_C_CN_FRAGLEN_HEADER_BYTES))
1612        {
1613            /*
1614             * We don't know the fragment length and we have enough bytes to
1615             * determine it so compute the fragment length.
1616             */
1617            frag_length = RPC_CN_PKT_FRAG_LEN ((rpc_cn_packet_p_t)(fbp->data_p));
1618
1619            /*
1620             * Swap bytes if our integer formats are different.
1621             */
1622            if (NDR_DREP_INT_REP( RPC_CN_PKT_DREP((rpc_cn_packet_p_t)fbp->data_p) ) != NDR_LOCAL_INT_REP)
1623            {
1624                SWAB_INPLACE_16 (frag_length);
1625            }
1626
1627            /*
1628             * Sanity check the protocol versions in the header.
1629             * Except for BIND and BIND_NAK packets.
1630             */
1631            {
1632                unsigned32 ptype;
1633                ptype = RPC_CN_PKT_PTYPE((rpc_cn_packet_p_t)fbp->data_p);
1634
1635                if ((ptype != RPC_C_CN_PKT_BIND) &&
1636                    (ptype != RPC_C_CN_PKT_BIND_NAK) &&
1637                    ((RPC_CN_PKT_VERS ((rpc_cn_packet_p_t)fbp->data_p) != RPC_C_CN_PROTO_VERS) ||
1638                     (RPC_CN_PKT_VERS_MINOR ((rpc_cn_packet_p_t)fbp->data_p) != assoc->assoc_vers_minor)))
1639                {
1640                    /*
1641                     * We have incompatible protocol versions.
1642                     */
1643                    /*
1644                     * "(receive_packet) assoc->%p %s: Protocol version mismatch -
1645                     *            major->%x minor->%x"
1646                     */
1647                    rpc_dce_svc_printf (
1648                        __FILE__, __LINE__,
1649                        "%x %s %x %x",
1650                        rpc_svc_cn_pkt,
1651                        svc_c_sev_warning,
1652                        rpc_m_prot_mismatch,
1653                        assoc,
1654                        rpc__cn_pkt_name(ptype),
1655                        RPC_CN_PKT_VERS ((rpc_cn_packet_p_t)fbp->data_p),
1656                        RPC_CN_PKT_VERS_MINOR ((rpc_cn_packet_p_t)fbp->data_p) );
1657                }
1658            }
1659
1660            /*
1661             * Sanity check the fragment size.
1662             * Signal an error if this fragment is bigger than a fragbuf.
1663             */
1664            if (frag_length > rpc_g_cn_large_frag_size)
1665            {
1666                unsigned32 ptype;
1667                ptype = RPC_CN_PKT_PTYPE((rpc_cn_packet_p_t)fbp->data_p);
1668
1669                /*
1670                 * "(receive_packet) assoc->%p frag_length %d in header >
1671                 *                fragbuf data size %d"
1672                 */
1673                rpc_dce_svc_printf (
1674                    __FILE__, __LINE__,
1675                    "%x %d %d",
1676                    rpc_svc_cn_pkt,
1677                    svc_c_sev_warning,
1678                    rpc_m_frag_toobig,
1679                    assoc,
1680                    frag_length,
1681                    rpc_g_cn_large_frag_size );
1682
1683                /*
1684                 * BIND and ALTER_CONTEXT are allowed to be larger
1685                 */
1686                if ((ptype == RPC_C_CN_PKT_BIND) ||
1687                    (ptype == RPC_C_CN_PKT_ALTER_CONTEXT))
1688                {
1689                    rpc_cn_fragbuf_t * volatile tmp;
1690
1691                    tmp = rpc__cn_fragbuf_alloc_dyn(frag_length);
1692                    tmp->data_size = fbp->data_size;
1693                    memcpy(tmp->data_p, fbp->data_p, fbp->data_size);
1694
1695                    (*fbp->fragbuf_dealloc)(fbp);
1696                    fbp = tmp;
1697                }
1698                else
1699                {
1700                   *st = rpc_s_protocol_error;
1701
1702                   /*
1703                    * Deallocate the fragbuf which we were using.
1704                    */
1705                   (*fbp->fragbuf_dealloc)(fbp);
1706                   return;
1707                }
1708            }
1709        }
1710
1711        /*
1712         * Recalculate how many bytes we need to complete this fragment.
1713         */
1714        if (frag_length == 0)
1715        {
1716            need_bytes = fbp->max_data_size - fbp->data_size;
1717        }
1718        else
1719        {
1720            need_bytes = frag_length - fbp->data_size;
1721        }
1722    } /* end of while(need_bytes > 0) */
1723
1724    /*
1725     * Handle the situation where we have read too much data.
1726     * This means that we have read into the next packet.
1727     * So, get an "overflow" fragment buffer and copy the excess data into it.
1728     */
1729
1730    /*
1731     * There is room for some optimization here.  If we have enough bytes to
1732     * determine the length of the next packet and the whole thing will fit into
1733     * a small fragbuf, then we should probably use a small one.  For now, we're
1734     * going to apply the KISS principle.
1735     */
1736    if (need_bytes < 0)
1737    {
1738        /*
1739         * Get an overflow fragment buffer.
1740         */
1741        *ovf_fragbuf_p = rpc__cn_fragbuf_alloc (true);
1742        (*ovf_fragbuf_p)->data_size = abs(need_bytes);
1743
1744        /*
1745         * Set the fragbuf data size to the fragment length and copy the
1746         * excess data to the overflow fragment buffer.
1747         */
1748        fbp->data_size = frag_length;
1749        memcpy ((*ovf_fragbuf_p)->data_p,
1750                (dce_pointer_t)((unsigned8 *)(fbp->data_p) + fbp->data_size),
1751                (*ovf_fragbuf_p)->data_size);
1752    }
1753
1754    /*
1755     * Return a pointer to the just-received packet along with okay status.
1756     */
1757    *fragbuf_p = fbp;
1758    *st = rpc_s_ok;
1759    RPC_LOG_CN_RCV_PKT_XIT;
1760}
1761