4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
27 * Server side RPC handler.
30 #include <sys/byteorder.h>
41 #define NDR_PIPE_SEND(np, buf, len) \
42 ((np)->np_send)((np), (buf), (len))
43 #define NDR_PIPE_RECV(np, buf, len) \
44 ((np)->np_recv)((np), (buf), (len))
46 static int ndr_svc_process(ndr_xa_t
*);
47 static int ndr_svc_bind(ndr_xa_t
*);
48 static int ndr_svc_request(ndr_xa_t
*);
49 static void ndr_reply_prepare_hdr(ndr_xa_t
*);
50 static int ndr_svc_alter_context(ndr_xa_t
*);
51 static void ndr_reply_fault(ndr_xa_t
*, unsigned long);
53 static int ndr_recv_request(ndr_xa_t
*mxa
);
54 static int ndr_recv_frag(ndr_xa_t
*mxa
);
55 static int ndr_send_reply(ndr_xa_t
*);
57 static int ndr_pipe_process(ndr_pipe_t
*, ndr_xa_t
*);
60 * External entry point called by smbd.
63 ndr_pipe_worker(ndr_pipe_t
*np
)
68 ndr_svc_binding_pool_init(&np
->np_binding
, np
->np_binding_pool
,
71 if ((mxa
= malloc(sizeof (*mxa
))) == NULL
)
75 bzero(mxa
, sizeof (*mxa
));
76 rc
= ndr_pipe_process(np
, mxa
);
82 * Ensure that there are no RPC service policy handles
83 * (associated with this fid) left around.
89 * Process one server-side RPC request.
92 ndr_pipe_process(ndr_pipe_t
*np
, ndr_xa_t
*mxa
)
94 ndr_stream_t
*recv_nds
;
95 ndr_stream_t
*send_nds
;
99 mxa
->binding_list
= np
->np_binding
;
101 if ((mxa
->heap
= ndr_heap_create()) == NULL
)
104 recv_nds
= &mxa
->recv_nds
;
105 rc
= nds_initialize(recv_nds
, 0, NDR_MODE_CALL_RECV
, mxa
->heap
);
109 send_nds
= &mxa
->send_nds
;
110 rc
= nds_initialize(send_nds
, 0, NDR_MODE_RETURN_SEND
, mxa
->heap
);
114 rc
= ndr_recv_request(mxa
);
118 (void) ndr_svc_process(mxa
);
119 (void) ndr_send_reply(mxa
);
123 nds_destruct(&mxa
->send_nds
);
125 nds_destruct(&mxa
->recv_nds
);
127 ndr_heap_destroy(mxa
->heap
);
133 * Receive an entire RPC request (all fragments)
134 * Returns zero or an NDR fault code.
137 ndr_recv_request(ndr_xa_t
*mxa
)
139 ndr_common_header_t
*hdr
= &mxa
->recv_hdr
.common_hdr
;
140 ndr_stream_t
*nds
= &mxa
->recv_nds
;
141 unsigned long saved_size
;
144 rc
= ndr_recv_frag(mxa
);
147 if (!NDR_IS_FIRST_FRAG(hdr
->pfc_flags
))
148 return (NDR_DRC_FAULT_DECODE_FAILED
);
150 while (!NDR_IS_LAST_FRAG(hdr
->pfc_flags
)) {
151 rc
= ndr_recv_frag(mxa
);
155 nds
->pdu_scan_offset
= 0;
158 * This whacks nds->pdu_size, so save/restore.
159 * It leaves scan_offset after the header.
161 saved_size
= nds
->pdu_size
;
162 rc
= ndr_decode_pdu_hdr(mxa
);
163 nds
->pdu_size
= saved_size
;
169 * Read one fragment, leaving the decoded frag header in
170 * recv_hdr.common_hdr, and the data in the recv_nds.
172 * Returns zero or an NDR fault code.
174 * If a first frag, the header is included in the data
175 * placed in recv_nds (because it's not fully decoded
176 * until later - we only decode the common part here).
177 * Additional frags are placed in the recv_nds without
178 * the header, so that after the first frag header,
179 * the remaining data will be contiguous. We do this
180 * by simply not advancing the offset in recv_nds after
181 * reading and decoding these additional fragments, so
182 * the payload of such frags will overwrite what was
183 * (temporarily) the frag header.
186 ndr_recv_frag(ndr_xa_t
*mxa
)
188 ndr_common_header_t
*hdr
= &mxa
->recv_hdr
.common_hdr
;
189 ndr_stream_t
*nds
= &mxa
->recv_nds
;
191 unsigned long next_offset
;
192 unsigned long pay_size
;
195 /* Make room for the frag header. */
196 next_offset
= nds
->pdu_scan_offset
+ NDR_RSP_HDR_SIZE
;
197 if (!NDS_GROW_PDU(nds
, next_offset
, 0))
198 return (NDR_DRC_FAULT_OUT_OF_MEMORY
);
200 /* Read the frag header. */
201 data
= nds
->pdu_base_addr
+ nds
->pdu_scan_offset
;
202 rc
= NDR_PIPE_RECV(mxa
->pipe
, data
, NDR_RSP_HDR_SIZE
);
204 return (NDR_DRC_FAULT_RPCHDR_RECEIVED_RUNT
);
207 * Decode the frag header, get the length.
208 * NB: It uses nds->pdu_scan_offset
210 ndr_decode_frag_hdr(nds
, hdr
);
212 if (hdr
->frag_length
< NDR_RSP_HDR_SIZE
||
213 hdr
->frag_length
> mxa
->pipe
->np_max_xmit_frag
)
214 return (NDR_DRC_FAULT_DECODE_FAILED
);
216 if (nds
->pdu_scan_offset
== 0) {
217 /* First frag: header stays in the data. */
218 nds
->pdu_scan_offset
= next_offset
;
219 } /* else overwrite with the payload */
221 /* Make room for the payload. */
222 pay_size
= hdr
->frag_length
- NDR_RSP_HDR_SIZE
;
223 next_offset
= nds
->pdu_scan_offset
+ pay_size
;
224 if (!NDS_GROW_PDU(nds
, next_offset
, 0))
225 return (NDR_DRC_FAULT_OUT_OF_MEMORY
);
227 /* Read the payload. */
228 data
= nds
->pdu_base_addr
+ nds
->pdu_scan_offset
;
229 rc
= NDR_PIPE_RECV(mxa
->pipe
, data
, pay_size
);
231 return (NDR_DRC_FAULT_RPCHDR_RECEIVED_RUNT
);
232 nds
->pdu_scan_offset
= next_offset
;
238 * This is the entry point for all server-side RPC processing.
239 * It is assumed that the PDU has already been received.
242 ndr_svc_process(ndr_xa_t
*mxa
)
246 (void) ndr_reply_prepare_hdr(mxa
);
248 switch (mxa
->ptype
) {
250 rc
= ndr_svc_bind(mxa
);
253 case NDR_PTYPE_REQUEST
:
254 rc
= ndr_svc_request(mxa
);
257 case NDR_PTYPE_ALTER_CONTEXT
:
258 rc
= ndr_svc_alter_context(mxa
);
262 rc
= NDR_DRC_FAULT_RPCHDR_PTYPE_INVALID
;
266 if (NDR_DRC_IS_FAULT(rc
))
267 ndr_reply_fault(mxa
, rc
);
273 * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple
274 * p_results[] not supported.
277 ndr_svc_bind(ndr_xa_t
*mxa
)
279 ndr_p_cont_list_t
*cont_list
;
280 ndr_p_result_list_t
*result_list
;
281 ndr_p_result_t
*result
;
283 ndr_binding_t
*mbind
;
290 ndr_port_any_t
*sec_addr
;
292 /* acquire targets */
293 cont_list
= &mxa
->recv_hdr
.bind_hdr
.p_context_elem
;
294 result_list
= &mxa
->send_hdr
.bind_ack_hdr
.p_result_list
;
295 result
= &result_list
->p_results
[0];
298 * Set up temporary secondary address port.
299 * We will correct this later (below).
301 sec_addr
= &mxa
->send_hdr
.bind_ack_hdr
.sec_addr
;
302 sec_addr
->length
= 13;
303 (void) strcpy((char *)sec_addr
->port_spec
, "\\PIPE\\ntsvcs");
305 result_list
->n_results
= 1;
306 result_list
->reserved
= 0;
307 result_list
->reserved2
= 0;
308 result
->result
= NDR_PCDR_ACCEPTANCE
;
310 bzero(&result
->transfer_syntax
, sizeof (result
->transfer_syntax
));
313 if (cont_list
->n_context_elem
!= 1 ||
314 cont_list
->p_cont_elem
[0].n_transfer_syn
!= 1) {
315 ndo_trace("ndr_svc_bind: warning: multiple p_cont_elem");
318 p_cont_id
= cont_list
->p_cont_elem
[0].p_cont_id
;
320 if ((mbind
= ndr_svc_find_binding(mxa
, p_cont_id
)) != NULL
) {
322 * Duplicate presentation context id.
324 ndo_trace("ndr_svc_bind: duplicate binding");
325 return (NDR_DRC_FAULT_BIND_PCONT_BUSY
);
328 if ((mbind
= ndr_svc_new_binding(mxa
)) == NULL
) {
330 * No free binding slot
332 result
->result
= NDR_PCDR_PROVIDER_REJECTION
;
333 result
->reason
= NDR_PPR_LOCAL_LIMIT_EXCEEDED
;
334 ndo_trace("ndr_svc_bind: no resources");
338 as_uuid
= &cont_list
->p_cont_elem
[0].abstract_syntax
.if_uuid
;
339 as_vers
= cont_list
->p_cont_elem
[0].abstract_syntax
.if_version
;
341 ts_uuid
= &cont_list
->p_cont_elem
[0].transfer_syntaxes
[0].if_uuid
;
342 ts_vers
= cont_list
->p_cont_elem
[0].transfer_syntaxes
[0].if_version
;
344 msvc
= ndr_svc_lookup_uuid(as_uuid
, as_vers
, ts_uuid
, ts_vers
);
346 result
->result
= NDR_PCDR_PROVIDER_REJECTION
;
347 result
->reason
= NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED
;
352 * We can now use the correct secondary address port.
354 sec_addr
= &mxa
->send_hdr
.bind_ack_hdr
.sec_addr
;
355 sec_addr
->length
= strlen(msvc
->sec_addr_port
) + 1;
356 (void) strlcpy((char *)sec_addr
->port_spec
, msvc
->sec_addr_port
,
357 NDR_PORT_ANY_MAX_PORT_SPEC
);
359 mbind
->p_cont_id
= p_cont_id
;
360 mbind
->which_side
= NDR_BIND_SIDE_SERVER
;
361 /* mbind->context set by app */
362 mbind
->service
= msvc
;
363 mbind
->instance_specific
= 0;
365 mxa
->binding
= mbind
;
367 if (msvc
->bind_req
) {
369 * Call the service-specific bind() handler. If
370 * this fails, we shouild send a specific error
373 rc
= (msvc
->bind_req
)(mxa
);
374 if (NDR_DRC_IS_FAULT(rc
)) {
375 mbind
->service
= 0; /* free binding slot */
376 mbind
->which_side
= 0;
377 mbind
->p_cont_id
= 0;
378 mbind
->instance_specific
= 0;
383 result
->transfer_syntax
=
384 cont_list
->p_cont_elem
[0].transfer_syntaxes
[0];
386 return (NDR_DRC_BINDING_MADE
);
390 * ndr_svc_alter_context
392 * The alter context request is used to request additional presentation
393 * context for another interface and/or version. It is very similar to
397 ndr_svc_alter_context(ndr_xa_t
*mxa
)
399 ndr_p_result_list_t
*result_list
;
400 ndr_p_result_t
*result
;
401 ndr_p_cont_list_t
*cont_list
;
402 ndr_binding_t
*mbind
;
409 ndr_port_any_t
*sec_addr
;
411 result_list
= &mxa
->send_hdr
.alter_context_rsp_hdr
.p_result_list
;
412 result_list
->n_results
= 1;
413 result_list
->reserved
= 0;
414 result_list
->reserved2
= 0;
416 result
= &result_list
->p_results
[0];
417 result
->result
= NDR_PCDR_ACCEPTANCE
;
419 bzero(&result
->transfer_syntax
, sizeof (result
->transfer_syntax
));
421 cont_list
= &mxa
->recv_hdr
.alter_context_hdr
.p_context_elem
;
422 p_cont_id
= cont_list
->p_cont_elem
[0].p_cont_id
;
424 if (ndr_svc_find_binding(mxa
, p_cont_id
) != NULL
)
425 return (NDR_DRC_FAULT_BIND_PCONT_BUSY
);
427 if ((mbind
= ndr_svc_new_binding(mxa
)) == NULL
) {
428 result
->result
= NDR_PCDR_PROVIDER_REJECTION
;
429 result
->reason
= NDR_PPR_LOCAL_LIMIT_EXCEEDED
;
433 as_uuid
= &cont_list
->p_cont_elem
[0].abstract_syntax
.if_uuid
;
434 as_vers
= cont_list
->p_cont_elem
[0].abstract_syntax
.if_version
;
436 ts_uuid
= &cont_list
->p_cont_elem
[0].transfer_syntaxes
[0].if_uuid
;
437 ts_vers
= cont_list
->p_cont_elem
[0].transfer_syntaxes
[0].if_version
;
439 msvc
= ndr_svc_lookup_uuid(as_uuid
, as_vers
, ts_uuid
, ts_vers
);
441 result
->result
= NDR_PCDR_PROVIDER_REJECTION
;
442 result
->reason
= NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED
;
446 mbind
->p_cont_id
= p_cont_id
;
447 mbind
->which_side
= NDR_BIND_SIDE_SERVER
;
448 /* mbind->context set by app */
449 mbind
->service
= msvc
;
450 mbind
->instance_specific
= 0;
451 mxa
->binding
= mbind
;
453 sec_addr
= &mxa
->send_hdr
.alter_context_rsp_hdr
.sec_addr
;
454 sec_addr
->length
= 0;
455 bzero(sec_addr
->port_spec
, NDR_PORT_ANY_MAX_PORT_SPEC
);
457 result
->transfer_syntax
=
458 cont_list
->p_cont_elem
[0].transfer_syntaxes
[0];
460 return (NDR_DRC_BINDING_MADE
);
464 ndr_svc_request(ndr_xa_t
*mxa
)
466 ndr_binding_t
*mbind
;
471 mxa
->opnum
= mxa
->recv_hdr
.request_hdr
.opnum
;
472 p_cont_id
= mxa
->recv_hdr
.request_hdr
.p_cont_id
;
474 if ((mbind
= ndr_svc_find_binding(mxa
, p_cont_id
)) == NULL
)
475 return (NDR_DRC_FAULT_REQUEST_PCONT_INVALID
);
477 mxa
->binding
= mbind
;
478 msvc
= mbind
->service
;
481 * Make room for the response hdr.
483 mxa
->send_nds
.pdu_scan_offset
= NDR_RSP_HDR_SIZE
;
486 rc
= (*msvc
->call_stub
)(mxa
);
488 rc
= ndr_generic_call_stub(mxa
);
490 if (NDR_DRC_IS_FAULT(rc
)) {
491 ndo_printf(0, 0, "%s[0x%02x]: 0x%04x",
492 msvc
->name
, mxa
->opnum
, rc
);
499 * The transaction and the two nds streams use the same heap, which
500 * should already exist at this point. The heap will also be available
504 ndr_generic_call_stub(ndr_xa_t
*mxa
)
506 ndr_binding_t
*mbind
= mxa
->binding
;
507 ndr_service_t
*msvc
= mbind
->service
;
508 ndr_typeinfo_t
*intf_ti
= msvc
->interface_ti
;
509 ndr_stub_table_t
*ste
;
510 int opnum
= mxa
->opnum
;
511 unsigned p_len
= intf_ti
->c_size_fixed_part
;
515 if (mxa
->heap
== NULL
) {
516 ndo_printf(0, 0, "%s[0x%02x]: no heap", msvc
->name
, opnum
);
517 return (NDR_DRC_FAULT_OUT_OF_MEMORY
);
520 if ((ste
= ndr_svc_find_stub(msvc
, opnum
)) == NULL
) {
521 ndo_printf(0, 0, "%s[0x%02x]: invalid opnum",
523 return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID
);
526 if ((param
= ndr_heap_malloc(mxa
->heap
, p_len
)) == NULL
)
527 return (NDR_DRC_FAULT_OUT_OF_MEMORY
);
531 rc
= ndr_decode_call(mxa
, param
);
532 if (!NDR_DRC_IS_OK(rc
))
535 rc
= (*ste
->func
)(param
, mxa
);
536 if (rc
== NDR_DRC_OK
)
537 rc
= ndr_encode_return(mxa
, param
);
543 * We can perform some initial setup of the response header here.
544 * We also need to cache some of the information from the bind
545 * negotiation for use during subsequent RPC calls.
548 ndr_reply_prepare_hdr(ndr_xa_t
*mxa
)
550 ndr_common_header_t
*rhdr
= &mxa
->recv_hdr
.common_hdr
;
551 ndr_common_header_t
*hdr
= &mxa
->send_hdr
.common_hdr
;
554 hdr
->rpc_vers_minor
= 0;
555 hdr
->pfc_flags
= NDR_PFC_FIRST_FRAG
+ NDR_PFC_LAST_FRAG
;
556 hdr
->packed_drep
= rhdr
->packed_drep
;
557 hdr
->frag_length
= 0;
558 hdr
->auth_length
= 0;
559 hdr
->call_id
= rhdr
->call_id
;
561 hdr
->packed_drep
.intg_char_rep
= NDR_REPLAB_CHAR_ASCII
562 | NDR_REPLAB_INTG_BIG_ENDIAN
;
564 hdr
->packed_drep
.intg_char_rep
= NDR_REPLAB_CHAR_ASCII
565 | NDR_REPLAB_INTG_LITTLE_ENDIAN
;
568 switch (mxa
->ptype
) {
571 * Compute the maximum fragment sizes for xmit/recv
572 * and store in the pipe endpoint. Note "xmit" is
573 * client-to-server; "recv" is server-to-client.
575 if (mxa
->pipe
->np_max_xmit_frag
>
576 mxa
->recv_hdr
.bind_hdr
.max_xmit_frag
)
577 mxa
->pipe
->np_max_xmit_frag
=
578 mxa
->recv_hdr
.bind_hdr
.max_xmit_frag
;
579 if (mxa
->pipe
->np_max_recv_frag
>
580 mxa
->recv_hdr
.bind_hdr
.max_recv_frag
)
581 mxa
->pipe
->np_max_recv_frag
=
582 mxa
->recv_hdr
.bind_hdr
.max_recv_frag
;
584 hdr
->ptype
= NDR_PTYPE_BIND_ACK
;
585 mxa
->send_hdr
.bind_ack_hdr
.max_xmit_frag
=
586 mxa
->pipe
->np_max_xmit_frag
;
587 mxa
->send_hdr
.bind_ack_hdr
.max_recv_frag
=
588 mxa
->pipe
->np_max_recv_frag
;
591 * We're supposed to assign a unique "assoc group"
592 * (identifies this connection for the client).
593 * Using the pipe address is adequate.
595 mxa
->send_hdr
.bind_ack_hdr
.assoc_group_id
=
596 mxa
->recv_hdr
.bind_hdr
.assoc_group_id
;
597 if (mxa
->send_hdr
.bind_ack_hdr
.assoc_group_id
== 0)
598 mxa
->send_hdr
.bind_ack_hdr
.assoc_group_id
=
599 (DWORD
)(uintptr_t)mxa
->pipe
;
603 case NDR_PTYPE_REQUEST
:
604 hdr
->ptype
= NDR_PTYPE_RESPONSE
;
605 /* mxa->send_hdr.response_hdr.alloc_hint */
606 mxa
->send_hdr
.response_hdr
.p_cont_id
=
607 mxa
->recv_hdr
.request_hdr
.p_cont_id
;
608 mxa
->send_hdr
.response_hdr
.cancel_count
= 0;
609 mxa
->send_hdr
.response_hdr
.reserved
= 0;
612 case NDR_PTYPE_ALTER_CONTEXT
:
613 hdr
->ptype
= NDR_PTYPE_ALTER_CONTEXT_RESP
;
615 * The max_xmit_frag, max_recv_frag and assoc_group_id are
616 * ignored by the client but it's useful to fill them in.
618 mxa
->send_hdr
.alter_context_rsp_hdr
.max_xmit_frag
=
619 mxa
->recv_hdr
.alter_context_hdr
.max_xmit_frag
;
620 mxa
->send_hdr
.alter_context_rsp_hdr
.max_recv_frag
=
621 mxa
->recv_hdr
.alter_context_hdr
.max_recv_frag
;
622 mxa
->send_hdr
.alter_context_rsp_hdr
.assoc_group_id
=
623 mxa
->recv_hdr
.alter_context_hdr
.assoc_group_id
;
632 * Signal an RPC fault. The stream is reset and we overwrite whatever
633 * was in the response header with the fault information.
636 ndr_reply_fault(ndr_xa_t
*mxa
, unsigned long drc
)
638 ndr_common_header_t
*rhdr
= &mxa
->recv_hdr
.common_hdr
;
639 ndr_common_header_t
*hdr
= &mxa
->send_hdr
.common_hdr
;
640 ndr_stream_t
*nds
= &mxa
->send_nds
;
641 unsigned long fault_status
;
646 hdr
->rpc_vers_minor
= 0;
647 hdr
->pfc_flags
= NDR_PFC_FIRST_FRAG
+ NDR_PFC_LAST_FRAG
;
648 hdr
->packed_drep
= rhdr
->packed_drep
;
649 hdr
->frag_length
= sizeof (mxa
->send_hdr
.fault_hdr
);
650 hdr
->auth_length
= 0;
651 hdr
->call_id
= rhdr
->call_id
;
653 hdr
->packed_drep
.intg_char_rep
= NDR_REPLAB_CHAR_ASCII
654 | NDR_REPLAB_INTG_BIG_ENDIAN
;
656 hdr
->packed_drep
.intg_char_rep
= NDR_REPLAB_CHAR_ASCII
657 | NDR_REPLAB_INTG_LITTLE_ENDIAN
;
660 switch (drc
& NDR_DRC_MASK_SPECIFIER
) {
661 case NDR_DRC_FAULT_OUT_OF_MEMORY
:
662 case NDR_DRC_FAULT_ENCODE_TOO_BIG
:
663 fault_status
= NDR_FAULT_NCA_OUT_ARGS_TOO_BIG
;
666 case NDR_DRC_FAULT_REQUEST_PCONT_INVALID
:
667 fault_status
= NDR_FAULT_NCA_INVALID_PRES_CONTEXT_ID
;
670 case NDR_DRC_FAULT_REQUEST_OPNUM_INVALID
:
671 fault_status
= NDR_FAULT_NCA_OP_RNG_ERROR
;
674 case NDR_DRC_FAULT_DECODE_FAILED
:
675 case NDR_DRC_FAULT_ENCODE_FAILED
:
676 fault_status
= NDR_FAULT_NCA_PROTO_ERROR
;
680 fault_status
= NDR_FAULT_NCA_UNSPEC_REJECT
;
684 mxa
->send_hdr
.fault_hdr
.common_hdr
.ptype
= NDR_PTYPE_FAULT
;
685 mxa
->send_hdr
.fault_hdr
.status
= fault_status
;
686 mxa
->send_hdr
.response_hdr
.alloc_hint
= hdr
->frag_length
;
690 * Note that the frag_length for bind ack and alter context is
694 ndr_send_reply(ndr_xa_t
*mxa
)
696 ndr_common_header_t
*hdr
= &mxa
->send_hdr
.common_hdr
;
697 ndr_stream_t
*nds
= &mxa
->send_nds
;
699 unsigned long pdu_size
;
700 unsigned long frag_size
;
701 unsigned long pdu_data_size
;
702 unsigned long frag_data_size
;
704 frag_size
= mxa
->pipe
->np_max_recv_frag
;
705 pdu_size
= nds
->pdu_size
;
706 pdu_buf
= nds
->pdu_base_addr
;
708 if (pdu_size
<= frag_size
) {
710 * Single fragment response. The PDU size may be zero
711 * here (i.e. bind or fault response). So don't make
712 * any assumptions about it until after the header is
715 switch (hdr
->ptype
) {
716 case NDR_PTYPE_BIND_ACK
:
717 hdr
->frag_length
= ndr_bind_ack_hdr_size(mxa
);
720 case NDR_PTYPE_FAULT
:
724 case NDR_PTYPE_RESPONSE
:
725 hdr
->frag_length
= pdu_size
;
726 mxa
->send_hdr
.response_hdr
.alloc_hint
=
730 case NDR_PTYPE_ALTER_CONTEXT_RESP
:
731 hdr
->frag_length
= ndr_alter_context_rsp_hdr_size();
735 hdr
->frag_length
= pdu_size
;
739 nds
->pdu_scan_offset
= 0;
740 (void) ndr_encode_pdu_hdr(mxa
);
741 pdu_size
= nds
->pdu_size
;
742 (void) NDR_PIPE_SEND(mxa
->pipe
, pdu_buf
, pdu_size
);
747 * Multiple fragment response.
749 * We need to update the RPC header for every fragment.
751 * pdu_data_size: total data remaining to be handled
752 * frag_size: total fragment size including header
753 * frag_data_size: data in fragment
754 * (i.e. frag_size - NDR_RSP_HDR_SIZE)
756 pdu_data_size
= pdu_size
- NDR_RSP_HDR_SIZE
;
757 frag_data_size
= frag_size
- NDR_RSP_HDR_SIZE
;
760 * Send the first frag.
762 hdr
->pfc_flags
= NDR_PFC_FIRST_FRAG
;
763 hdr
->frag_length
= frag_size
;
764 mxa
->send_hdr
.response_hdr
.alloc_hint
= pdu_data_size
;
765 nds
->pdu_scan_offset
= 0;
766 (void) ndr_encode_pdu_hdr(mxa
);
767 (void) NDR_PIPE_SEND(mxa
->pipe
, pdu_buf
, frag_size
);
768 pdu_data_size
-= frag_data_size
;
769 pdu_buf
+= frag_data_size
;
772 * Send "middle" (full-sized) fragments...
775 while (pdu_data_size
> frag_data_size
) {
777 hdr
->frag_length
= frag_size
;
778 mxa
->send_hdr
.response_hdr
.alloc_hint
= pdu_data_size
;
779 nds
->pdu_scan_offset
= 0;
780 (void) ndr_encode_pdu_hdr(mxa
);
781 bcopy(nds
->pdu_base_addr
, pdu_buf
, NDR_RSP_HDR_SIZE
);
782 (void) NDR_PIPE_SEND(mxa
->pipe
, pdu_buf
, frag_size
);
783 pdu_data_size
-= frag_data_size
;
784 pdu_buf
+= frag_data_size
;
788 * Last frag (pdu_data_size <= frag_data_size)
790 hdr
->pfc_flags
= NDR_PFC_LAST_FRAG
;
791 frag_size
= pdu_data_size
+ NDR_RSP_HDR_SIZE
;
792 hdr
->frag_length
= frag_size
;
793 mxa
->send_hdr
.response_hdr
.alloc_hint
= pdu_data_size
;
794 nds
->pdu_scan_offset
= 0;
795 (void) ndr_encode_pdu_hdr(mxa
);
796 bcopy(nds
->pdu_base_addr
, pdu_buf
, NDR_RSP_HDR_SIZE
);
797 (void) NDR_PIPE_SEND(mxa
->pipe
, pdu_buf
, frag_size
);