15772Sas200622 /* 25772Sas200622 * CDDL HEADER START 35772Sas200622 * 45772Sas200622 * The contents of this file are subject to the terms of the 55772Sas200622 * Common Development and Distribution License (the "License"). 65772Sas200622 * You may not use this file except in compliance with the License. 75772Sas200622 * 85772Sas200622 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95772Sas200622 * or http://www.opensolaris.org/os/licensing. 105772Sas200622 * See the License for the specific language governing permissions 115772Sas200622 * and limitations under the License. 125772Sas200622 * 135772Sas200622 * When distributing Covered Code, include this CDDL HEADER in each 145772Sas200622 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155772Sas200622 * If applicable, add the following below this CDDL HEADER, with the 165772Sas200622 * fields enclosed by brackets "[]" replaced with your own identifying 175772Sas200622 * information: Portions Copyright [yyyy] [name of copyright owner] 185772Sas200622 * 195772Sas200622 * CDDL HEADER END 205772Sas200622 */ 215772Sas200622 /* 225772Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235772Sas200622 * Use is subject to license terms. 245772Sas200622 */ 255772Sas200622 265772Sas200622 /* 275772Sas200622 * Server side RPC handler. 285772Sas200622 */ 295772Sas200622 305772Sas200622 #include <sys/byteorder.h> 317052Samw #include <sys/errno.h> 327052Samw #include <sys/uio.h> 335772Sas200622 #include <thread.h> 345772Sas200622 #include <synch.h> 355772Sas200622 #include <stdlib.h> 365772Sas200622 #include <strings.h> 375772Sas200622 #include <string.h> 385772Sas200622 #include <time.h> 395772Sas200622 405772Sas200622 #include <smbsrv/libsmb.h> 415772Sas200622 #include <smbsrv/libmlrpc.h> 425772Sas200622 #include <smbsrv/mlsvc.h> 435772Sas200622 #include <smbsrv/ndr.h> 445772Sas200622 #include <smbsrv/mlrpc.h> 455772Sas200622 #include <smbsrv/mlsvc_util.h> 467052Samw 477052Samw 487052Samw #define SMB_CTXT_BUFSZ 65536 495772Sas200622 505772Sas200622 /* 515772Sas200622 * Fragment size (5680: NT style). 525772Sas200622 */ 535772Sas200622 #define MLRPC_FRAG_SZ 5680 545772Sas200622 static unsigned long mlrpc_frag_size = MLRPC_FRAG_SZ; 555772Sas200622 565772Sas200622 /* 577052Samw * Service context table. 585772Sas200622 */ 595772Sas200622 #define CTXT_TABLE_ENTRIES 128 605772Sas200622 static struct mlsvc_rpc_context context_table[CTXT_TABLE_ENTRIES]; 615772Sas200622 static mutex_t mlrpc_context_lock; 625772Sas200622 637052Samw static int ndr_s_transact(struct mlsvc_rpc_context *); 647052Samw static struct mlsvc_rpc_context *ndr_s_lookup(int); 657052Samw static void ndr_s_release(struct mlsvc_rpc_context *); 667052Samw static struct mlsvc_rpc_context *ndr_s_allocate(int); 677052Samw static void ndr_s_deallocate(struct mlsvc_rpc_context *); 687052Samw static void ndr_s_rewind(struct mlsvc_rpc_context *); 697052Samw static void ndr_s_flush(struct mlsvc_rpc_context *); 707052Samw 715772Sas200622 static int mlrpc_s_process(struct mlrpc_xaction *); 725772Sas200622 static int mlrpc_s_bind(struct mlrpc_xaction *); 735772Sas200622 static int mlrpc_s_request(struct mlrpc_xaction *); 745772Sas200622 static void mlrpc_reply_prepare_hdr(struct mlrpc_xaction *); 755772Sas200622 static int mlrpc_s_alter_context(struct mlrpc_xaction *); 765772Sas200622 static void mlrpc_reply_fault(struct mlrpc_xaction *, unsigned long); 775772Sas200622 static int mlrpc_build_reply(struct mlrpc_xaction *); 786482Samw static void mlrpc_build_frag(struct mlndr_stream *, uint8_t *, uint32_t); 795772Sas200622 805772Sas200622 /* 817052Samw * Allocate and associate a service context with a fid. 827052Samw */ 837052Samw int 847052Samw ndr_s_open(int fid, uint8_t *data, uint32_t datalen) 857052Samw { 867052Samw struct mlsvc_rpc_context *svc; 877052Samw 887052Samw (void) mutex_lock(&mlrpc_context_lock); 897052Samw 907052Samw if ((svc = ndr_s_lookup(fid)) != NULL) { 917052Samw ndr_s_release(svc); 927052Samw (void) mutex_unlock(&mlrpc_context_lock); 937052Samw return (EEXIST); 947052Samw } 957052Samw 967052Samw if ((svc = ndr_s_allocate(fid)) == NULL) { 977052Samw (void) mutex_unlock(&mlrpc_context_lock); 987052Samw return (ENOMEM); 997052Samw } 1007052Samw 1017052Samw if (smb_opipe_context_decode(&svc->svc_ctx, data, datalen) == -1) { 1027052Samw ndr_s_release(svc); 1037052Samw (void) mutex_unlock(&mlrpc_context_lock); 1047052Samw return (EINVAL); 1057052Samw } 1067052Samw 1077052Samw mlrpc_binding_pool_initialize(&svc->binding, svc->binding_pool, 1087052Samw CTXT_N_BINDING_POOL); 1097052Samw 1107052Samw (void) mutex_unlock(&mlrpc_context_lock); 1117052Samw return (0); 1127052Samw } 1137052Samw 1147052Samw /* 1157052Samw * Release the context associated with a fid when an opipe is closed. 1167052Samw */ 1177052Samw int 1187052Samw ndr_s_close(int fid) 1197052Samw { 1207052Samw struct mlsvc_rpc_context *svc; 1217052Samw 1227052Samw (void) mutex_lock(&mlrpc_context_lock); 1237052Samw 1247052Samw if ((svc = ndr_s_lookup(fid)) == NULL) { 1257052Samw (void) mutex_unlock(&mlrpc_context_lock); 1267052Samw return (ENOENT); 1277052Samw } 1287052Samw 1297052Samw /* 1307052Samw * Release twice: once for the lookup above 1317052Samw * and again to close the fid. 1327052Samw */ 1337052Samw ndr_s_release(svc); 1347052Samw ndr_s_release(svc); 1357052Samw (void) mutex_unlock(&mlrpc_context_lock); 1367052Samw return (0); 1377052Samw } 1387052Samw 1397052Samw /* 1407052Samw * Write RPC request data to the input stream. Input data is buffered 1417052Samw * until the response is requested. 1425772Sas200622 */ 1437052Samw int 1447052Samw ndr_s_write(int fid, uint8_t *buf, uint32_t len) 1457052Samw { 1467052Samw struct mlsvc_rpc_context *svc; 1477052Samw ssize_t nbytes; 1487052Samw 1497052Samw if (len == 0) 1507052Samw return (0); 1517052Samw 1527052Samw (void) mutex_lock(&mlrpc_context_lock); 1537052Samw 1547052Samw if ((svc = ndr_s_lookup(fid)) == NULL) { 1557052Samw (void) mutex_unlock(&mlrpc_context_lock); 1567052Samw return (ENOENT); 1577052Samw } 1587052Samw 1597052Samw nbytes = ndr_uiomove((caddr_t)buf, len, UIO_READ, &svc->in_uio); 1607052Samw 1617052Samw ndr_s_release(svc); 1627052Samw (void) mutex_unlock(&mlrpc_context_lock); 1637052Samw return ((nbytes == len) ? 0 : EIO); 1647052Samw } 1657052Samw 1667052Samw /* 1677052Samw * Read RPC response data. If the input stream contains an RPC request, 1687052Samw * we need to process the RPC transaction, which will place the RPC 1697052Samw * response in the output (frags) stream. Otherwise, read data from 1707052Samw * the output stream. 1717052Samw */ 1727052Samw int 1737052Samw ndr_s_read(int fid, uint8_t *buf, uint32_t *len, uint32_t *resid) 1745772Sas200622 { 1757052Samw struct mlsvc_rpc_context *svc; 1767052Samw ssize_t nbytes = *len; 1777052Samw int rc; 1787052Samw 1797052Samw if (nbytes == 0) { 1807052Samw *resid = 0; 1817052Samw return (0); 1827052Samw } 1837052Samw 1847052Samw (void) mutex_lock(&mlrpc_context_lock); 1857052Samw if ((svc = ndr_s_lookup(fid)) == NULL) { 1867052Samw (void) mutex_unlock(&mlrpc_context_lock); 1877052Samw return (ENOENT); 1887052Samw } 1897052Samw (void) mutex_unlock(&mlrpc_context_lock); 1907052Samw 1917052Samw if (svc->in_uio.uio_offset) { 1927052Samw if ((rc = ndr_s_transact(svc)) != 0) { 1937052Samw ndr_s_flush(svc); 1947052Samw (void) mutex_lock(&mlrpc_context_lock); 1957052Samw ndr_s_release(svc); 1967052Samw (void) mutex_unlock(&mlrpc_context_lock); 1977052Samw return (rc); 1987052Samw } 1997052Samw 2007052Samw } 2017052Samw 2027052Samw *len = ndr_uiomove((caddr_t)buf, nbytes, UIO_WRITE, &svc->frags.uio); 2037052Samw *resid = svc->frags.uio.uio_resid; 2047052Samw 2057052Samw if (*resid == 0) { 2067052Samw /* 2077052Samw * Nothing left, cleanup the output stream. 2087052Samw */ 2097052Samw ndr_s_flush(svc); 2107052Samw } 2117052Samw 2127052Samw (void) mutex_lock(&mlrpc_context_lock); 2137052Samw ndr_s_release(svc); 2147052Samw (void) mutex_unlock(&mlrpc_context_lock); 2157052Samw return (0); 2167052Samw } 2177052Samw 2187052Samw /* 2197052Samw * Process a server-side RPC request. 2207052Samw */ 2217052Samw static int 2227052Samw ndr_s_transact(struct mlsvc_rpc_context *svc) 2237052Samw { 2247052Samw ndr_xa_t *mxa; 2255772Sas200622 struct mlndr_stream *recv_mlnds; 2265772Sas200622 struct mlndr_stream *send_mlnds; 2275772Sas200622 char *data; 2285772Sas200622 int datalen; 2295772Sas200622 2307052Samw data = svc->in_buf; 2317052Samw datalen = svc->in_uio.uio_offset; 2325772Sas200622 2337052Samw if ((mxa = (ndr_xa_t *)malloc(sizeof (ndr_xa_t))) == NULL) 2347052Samw return (ENOMEM); 2355772Sas200622 2365772Sas200622 bzero(mxa, sizeof (struct mlrpc_xaction)); 2377052Samw mxa->fid = svc->fid; 2387052Samw mxa->context = svc; 2397052Samw mxa->binding_list = svc->binding; 2405772Sas200622 2415772Sas200622 if ((mxa->heap = mlrpc_heap_create()) == NULL) { 2425772Sas200622 free(mxa); 2437052Samw return (ENOMEM); 2445772Sas200622 } 2455772Sas200622 2465772Sas200622 recv_mlnds = &mxa->recv_mlnds; 2477052Samw mlnds_initialize(recv_mlnds, datalen, NDR_MODE_CALL_RECV, mxa->heap); 2485772Sas200622 2497052Samw /* 2507052Samw * Copy the input data and reset the input stream. 2517052Samw */ 2525772Sas200622 bcopy(data, recv_mlnds->pdu_base_addr, datalen); 2537052Samw ndr_s_rewind(svc); 2545772Sas200622 2555772Sas200622 send_mlnds = &mxa->send_mlnds; 2567052Samw mlnds_initialize(send_mlnds, 0, NDR_MODE_RETURN_SEND, mxa->heap); 2575772Sas200622 2585772Sas200622 (void) mlrpc_s_process(mxa); 2595772Sas200622 2607052Samw mlnds_finalize(send_mlnds, &svc->frags); 2615772Sas200622 mlnds_destruct(&mxa->recv_mlnds); 2625772Sas200622 mlnds_destruct(&mxa->send_mlnds); 2635772Sas200622 mlrpc_heap_destroy(mxa->heap); 2645772Sas200622 free(mxa); 2657052Samw return (0); 2667052Samw } 2677052Samw 2687052Samw /* 2697052Samw * Must be called with mlrpc_context_lock held. 2707052Samw */ 2717052Samw static struct mlsvc_rpc_context * 2727052Samw ndr_s_lookup(int fid) 2737052Samw { 2747052Samw struct mlsvc_rpc_context *svc; 2757052Samw int i; 2767052Samw 2777052Samw for (i = 0; i < CTXT_TABLE_ENTRIES; ++i) { 2787052Samw svc = &context_table[i]; 2797052Samw 2807052Samw if (svc->fid == fid) { 2817052Samw if (svc->refcnt == 0) 2827052Samw return (NULL); 2837052Samw 2847052Samw svc->refcnt++; 2857052Samw return (svc); 2867052Samw } 2877052Samw } 2887052Samw 2897052Samw return (NULL); 2905772Sas200622 } 2915772Sas200622 2925772Sas200622 /* 2937052Samw * Must be called with mlrpc_context_lock held. 2945772Sas200622 */ 2957052Samw static void 2967052Samw ndr_s_release(struct mlsvc_rpc_context *svc) 2975772Sas200622 { 2987052Samw svc->refcnt--; 2997052Samw ndr_s_deallocate(svc); 3007052Samw } 3017052Samw 3027052Samw /* 3037052Samw * Must be called with mlrpc_context_lock held. 3047052Samw */ 3057052Samw static struct mlsvc_rpc_context * 3067052Samw ndr_s_allocate(int fid) 3077052Samw { 3087052Samw struct mlsvc_rpc_context *svc = NULL; 3095772Sas200622 int i; 3105772Sas200622 3117052Samw for (i = 0; i < CTXT_TABLE_ENTRIES; ++i) { 3127052Samw svc = &context_table[i]; 3135772Sas200622 3147052Samw if (svc->fid == 0) { 3157052Samw bzero(svc, sizeof (struct mlsvc_rpc_context)); 3165772Sas200622 3177052Samw if ((svc->in_buf = malloc(SMB_CTXT_BUFSZ)) == NULL) 3187052Samw return (NULL); 3195772Sas200622 3207052Samw ndr_s_rewind(svc); 3217052Samw svc->fid = fid; 3227052Samw svc->refcnt = 1; 3237052Samw return (svc); 3245772Sas200622 } 3255772Sas200622 } 3265772Sas200622 3277052Samw return (NULL); 3287052Samw } 3295772Sas200622 3307052Samw /* 3317052Samw * Must be called with mlrpc_context_lock held. 3327052Samw */ 3337052Samw static void 3347052Samw ndr_s_deallocate(struct mlsvc_rpc_context *svc) 3357052Samw { 3367052Samw if (svc->refcnt == 0) { 3377052Samw /* 3387052Samw * Ensure that there are no RPC service policy handles 3397052Samw * (associated with this fid) left around. 3407052Samw */ 3417052Samw ndr_hdclose(svc->fid); 3425772Sas200622 3437052Samw ndr_s_rewind(svc); 3447052Samw ndr_s_flush(svc); 3457052Samw free(svc->in_buf); 3467052Samw free(svc->svc_ctx.oc_domain); 3477052Samw free(svc->svc_ctx.oc_account); 3487052Samw free(svc->svc_ctx.oc_workstation); 3497052Samw bzero(svc, sizeof (struct mlsvc_rpc_context)); 3507052Samw } 3517052Samw } 3525772Sas200622 3537052Samw /* 3547052Samw * Rewind the input data stream, ready for the next write. 3557052Samw */ 3567052Samw static void 3577052Samw ndr_s_rewind(struct mlsvc_rpc_context *svc) 3587052Samw { 3597052Samw svc->in_uio.uio_iov = &svc->in_iov; 3607052Samw svc->in_uio.uio_iovcnt = 1; 3617052Samw svc->in_uio.uio_offset = 0; 3627052Samw svc->in_uio.uio_segflg = UIO_USERSPACE; 3637052Samw svc->in_uio.uio_resid = SMB_CTXT_BUFSZ; 3647052Samw svc->in_iov.iov_base = svc->in_buf; 3657052Samw svc->in_iov.iov_len = SMB_CTXT_BUFSZ; 3665772Sas200622 } 3675772Sas200622 3685772Sas200622 /* 3697052Samw * Flush the output data stream. 3705772Sas200622 */ 3717052Samw static void 3727052Samw ndr_s_flush(struct mlsvc_rpc_context *svc) 3735772Sas200622 { 3747052Samw ndr_frag_t *frag; 3755772Sas200622 3767052Samw while ((frag = svc->frags.head) != NULL) { 3777052Samw svc->frags.head = frag->next; 3787052Samw free(frag); 3795772Sas200622 } 3805772Sas200622 3817052Samw free(svc->frags.iov); 3827052Samw bzero(&svc->frags, sizeof (ndr_fraglist_t)); 3837052Samw } 3847052Samw 3857052Samw /* 3867052Samw * Check whether or not the specified user has administrator privileges, 3877052Samw * i.e. is a member of Domain Admins or Administrators. 3887052Samw * Returns true if the user is an administrator, otherwise returns false. 3897052Samw */ 3907052Samw boolean_t 3917052Samw ndr_is_admin(ndr_xa_t *xa) 3927052Samw { 3937052Samw smb_opipe_context_t *svc = &xa->context->svc_ctx; 3947052Samw 3957052Samw return (svc->oc_flags & SMB_ATF_ADMIN); 3967052Samw } 3977052Samw 3987052Samw /* 3997052Samw * Check whether or not the specified user has power-user privileges, 4007052Samw * i.e. is a member of Domain Admins, Administrators or Power Users. 4017052Samw * This is typically required for operations such as managing shares. 4027052Samw * Returns true if the user is a power user, otherwise returns false. 4037052Samw */ 4047052Samw boolean_t 4057052Samw ndr_is_poweruser(ndr_xa_t *xa) 4067052Samw { 4077052Samw smb_opipe_context_t *svc = &xa->context->svc_ctx; 4087052Samw 4097052Samw return ((svc->oc_flags & SMB_ATF_ADMIN) || 4107052Samw (svc->oc_flags & SMB_ATF_POWERUSER)); 4117052Samw } 4127052Samw 4137052Samw int32_t 4147052Samw ndr_native_os(ndr_xa_t *xa) 4157052Samw { 4167052Samw smb_opipe_context_t *svc = &xa->context->svc_ctx; 4177052Samw 4187052Samw return (svc->oc_native_os); 4195772Sas200622 } 4205772Sas200622 4215772Sas200622 /* 4225772Sas200622 * This is the entry point for all server-side RPC processing. 4235772Sas200622 * It is assumed that the PDU has already been received. 4245772Sas200622 */ 4255772Sas200622 static int 4265772Sas200622 mlrpc_s_process(struct mlrpc_xaction *mxa) 4275772Sas200622 { 4285772Sas200622 int rc; 4295772Sas200622 4305772Sas200622 rc = mlrpc_decode_pdu_hdr(mxa); 4315772Sas200622 if (!MLRPC_DRC_IS_OK(rc)) 4325772Sas200622 return (-1); 4335772Sas200622 4345772Sas200622 (void) mlrpc_reply_prepare_hdr(mxa); 4355772Sas200622 4365772Sas200622 switch (mxa->ptype) { 4375772Sas200622 case MLRPC_PTYPE_BIND: 4385772Sas200622 rc = mlrpc_s_bind(mxa); 4395772Sas200622 break; 4405772Sas200622 4415772Sas200622 case MLRPC_PTYPE_REQUEST: 4425772Sas200622 rc = mlrpc_s_request(mxa); 4435772Sas200622 break; 4445772Sas200622 4455772Sas200622 case MLRPC_PTYPE_ALTER_CONTEXT: 4465772Sas200622 rc = mlrpc_s_alter_context(mxa); 4475772Sas200622 break; 4485772Sas200622 4495772Sas200622 default: 4505772Sas200622 rc = MLRPC_DRC_FAULT_RPCHDR_PTYPE_INVALID; 4515772Sas200622 break; 4525772Sas200622 } 4535772Sas200622 4545772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 4555772Sas200622 mlrpc_reply_fault(mxa, rc); 4565772Sas200622 4575772Sas200622 (void) mlrpc_build_reply(mxa); 4585772Sas200622 return (rc); 4595772Sas200622 } 4605772Sas200622 4615772Sas200622 /* 4625772Sas200622 * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple 4635772Sas200622 * p_results[] not supported. 4645772Sas200622 */ 4655772Sas200622 static int 4665772Sas200622 mlrpc_s_bind(struct mlrpc_xaction *mxa) 4675772Sas200622 { 4685772Sas200622 mlrpc_p_cont_list_t *cont_list; 4695772Sas200622 mlrpc_p_result_list_t *result_list; 4705772Sas200622 mlrpc_p_result_t *result; 4715772Sas200622 unsigned p_cont_id; 4725772Sas200622 struct mlrpc_binding *mbind; 4735772Sas200622 ndr_uuid_t *as_uuid; 4745772Sas200622 ndr_uuid_t *ts_uuid; 4755772Sas200622 char as_buf[64]; 4765772Sas200622 char ts_buf[64]; 4775772Sas200622 int as_vers; 4785772Sas200622 int ts_vers; 4795772Sas200622 struct mlndr_stream *send_mlnds; 4805772Sas200622 struct mlrpc_service *msvc; 4815772Sas200622 int rc; 4825772Sas200622 mlrpc_port_any_t *sec_addr; 4835772Sas200622 4845772Sas200622 /* acquire targets */ 4855772Sas200622 cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem; 4865772Sas200622 result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list; 4875772Sas200622 result = &result_list->p_results[0]; 4885772Sas200622 4895772Sas200622 /* 4905772Sas200622 * Set up temporary secondary address port. 4915772Sas200622 * We will correct this later (below). 4925772Sas200622 */ 4935772Sas200622 send_mlnds = &mxa->send_mlnds; 4945772Sas200622 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 4955772Sas200622 sec_addr->length = 13; 4965772Sas200622 (void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs"); 4975772Sas200622 4985772Sas200622 result_list->n_results = 1; 4995772Sas200622 result_list->reserved = 0; 5005772Sas200622 result_list->reserved2 = 0; 5015772Sas200622 result->result = MLRPC_PCDR_ACCEPTANCE; 5025772Sas200622 result->reason = 0; 5035772Sas200622 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax)); 5045772Sas200622 5055772Sas200622 /* sanity check */ 5065772Sas200622 if (cont_list->n_context_elem != 1 || 5075772Sas200622 cont_list->p_cont_elem[0].n_transfer_syn != 1) { 5085772Sas200622 mlndo_trace("mlrpc_s_bind: warning: multiple p_cont_elem"); 5095772Sas200622 } 5105772Sas200622 5115772Sas200622 p_cont_id = cont_list->p_cont_elem[0].p_cont_id; 5125772Sas200622 5135772Sas200622 if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) != NULL) { 5145772Sas200622 /* 5155772Sas200622 * Duplicate p_cont_id. 5165772Sas200622 * Send a bind_ack with a better error. 5175772Sas200622 */ 5185772Sas200622 mlndo_trace("mlrpc_s_bind: duplicate binding"); 5195772Sas200622 return (MLRPC_DRC_FAULT_BIND_PCONT_BUSY); 5205772Sas200622 } 5215772Sas200622 5225772Sas200622 if ((mbind = mlrpc_new_binding(mxa)) == NULL) { 5235772Sas200622 /* 5245772Sas200622 * No free binding slot 5255772Sas200622 */ 5265772Sas200622 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 5275772Sas200622 result->reason = MLRPC_PPR_LOCAL_LIMIT_EXCEEDED; 5285772Sas200622 mlndo_trace("mlrpc_s_bind: no resources"); 5295772Sas200622 return (MLRPC_DRC_OK); 5305772Sas200622 } 5315772Sas200622 5325772Sas200622 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid; 5335772Sas200622 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version; 5345772Sas200622 5355772Sas200622 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid; 5365772Sas200622 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version; 5375772Sas200622 5385772Sas200622 msvc = mlrpc_find_service_by_uuids(as_uuid, as_vers, ts_uuid, ts_vers); 5395772Sas200622 if (!msvc) { 5405772Sas200622 mlrpc_uuid_to_str(as_uuid, as_buf); 5415772Sas200622 mlrpc_uuid_to_str(ts_uuid, ts_buf); 5425772Sas200622 5435772Sas200622 mlndo_printf(send_mlnds, 0, "mlrpc_s_bind: unknown service"); 5445772Sas200622 mlndo_printf(send_mlnds, 0, "abs=%s v%d, xfer=%s v%d", 5455772Sas200622 as_buf, as_vers, ts_buf, ts_vers); 5465772Sas200622 5475772Sas200622 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 5485772Sas200622 result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 5495772Sas200622 return (MLRPC_DRC_OK); 5505772Sas200622 } 5515772Sas200622 5525772Sas200622 /* 5535772Sas200622 * We can now use the correct secondary address port. 5545772Sas200622 */ 5555772Sas200622 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 5565772Sas200622 sec_addr->length = strlen(msvc->sec_addr_port) + 1; 5575772Sas200622 (void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port, 5585772Sas200622 MLRPC_PORT_ANY_MAX_PORT_SPEC); 5595772Sas200622 5605772Sas200622 mbind->p_cont_id = p_cont_id; 5615772Sas200622 mbind->which_side = MLRPC_BIND_SIDE_SERVER; 5625772Sas200622 /* mbind->context set by app */ 5635772Sas200622 mbind->service = msvc; 5645772Sas200622 mbind->instance_specific = 0; 5655772Sas200622 5665772Sas200622 mxa->binding = mbind; 5675772Sas200622 5685772Sas200622 if (msvc->bind_req) { 5695772Sas200622 /* 5705772Sas200622 * Call the service-specific bind() handler. If 5715772Sas200622 * this fails, we shouild send a specific error 5725772Sas200622 * on the bind ack. 5735772Sas200622 */ 5745772Sas200622 rc = (msvc->bind_req)(mxa); 5755772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) { 5765772Sas200622 mbind->service = 0; /* free binding slot */ 5775772Sas200622 mbind->which_side = 0; 5785772Sas200622 mbind->p_cont_id = 0; 5795772Sas200622 mbind->instance_specific = 0; 5805772Sas200622 return (rc); 5815772Sas200622 } 5825772Sas200622 } 5835772Sas200622 5845772Sas200622 result->transfer_syntax = 5855772Sas200622 cont_list->p_cont_elem[0].transfer_syntaxes[0]; 5865772Sas200622 5875772Sas200622 return (MLRPC_DRC_BINDING_MADE); 5885772Sas200622 } 5895772Sas200622 5905772Sas200622 /* 5915772Sas200622 * mlrpc_s_alter_context 5925772Sas200622 * 5935772Sas200622 * The alter context request is used to request additional presentation 594*7619SJose.Borrego@Sun.COM * context for another interface and/or version. It is very similar to 595*7619SJose.Borrego@Sun.COM * a bind request. 5965772Sas200622 */ 5975772Sas200622 static int 5985772Sas200622 mlrpc_s_alter_context(struct mlrpc_xaction *mxa) 5995772Sas200622 { 6005772Sas200622 mlrpc_p_result_list_t *result_list; 6015772Sas200622 mlrpc_p_result_t *result; 6025772Sas200622 mlrpc_p_cont_list_t *cont_list; 6035772Sas200622 struct mlrpc_binding *mbind; 6045772Sas200622 struct mlrpc_service *msvc; 6055772Sas200622 unsigned p_cont_id; 6065772Sas200622 ndr_uuid_t *as_uuid; 6075772Sas200622 ndr_uuid_t *ts_uuid; 6085772Sas200622 int as_vers; 6095772Sas200622 int ts_vers; 6105772Sas200622 mlrpc_port_any_t *sec_addr; 6115772Sas200622 612*7619SJose.Borrego@Sun.COM result_list = &mxa->send_hdr.alter_context_rsp_hdr.p_result_list; 6135772Sas200622 result_list->n_results = 1; 6145772Sas200622 result_list->reserved = 0; 6155772Sas200622 result_list->reserved2 = 0; 6165772Sas200622 6175772Sas200622 result = &result_list->p_results[0]; 6185772Sas200622 result->result = MLRPC_PCDR_ACCEPTANCE; 6195772Sas200622 result->reason = 0; 6205772Sas200622 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax)); 6215772Sas200622 622*7619SJose.Borrego@Sun.COM cont_list = &mxa->recv_hdr.alter_context_hdr.p_context_elem; 6235772Sas200622 p_cont_id = cont_list->p_cont_elem[0].p_cont_id; 6245772Sas200622 625*7619SJose.Borrego@Sun.COM if (mlrpc_find_binding(mxa, p_cont_id) != NULL) 6265772Sas200622 return (MLRPC_DRC_FAULT_BIND_PCONT_BUSY); 6275772Sas200622 6285772Sas200622 if ((mbind = mlrpc_new_binding(mxa)) == NULL) { 6295772Sas200622 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 6305772Sas200622 result->reason = MLRPC_PPR_LOCAL_LIMIT_EXCEEDED; 6315772Sas200622 return (MLRPC_DRC_OK); 6325772Sas200622 } 6335772Sas200622 6345772Sas200622 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid; 6355772Sas200622 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version; 6365772Sas200622 6375772Sas200622 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid; 6385772Sas200622 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version; 6395772Sas200622 6405772Sas200622 msvc = mlrpc_find_service_by_uuids(as_uuid, as_vers, ts_uuid, ts_vers); 6415772Sas200622 if (msvc == 0) { 6425772Sas200622 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 6435772Sas200622 result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 6445772Sas200622 return (MLRPC_DRC_OK); 6455772Sas200622 } 6465772Sas200622 6475772Sas200622 mbind->p_cont_id = p_cont_id; 6485772Sas200622 mbind->which_side = MLRPC_BIND_SIDE_SERVER; 6495772Sas200622 /* mbind->context set by app */ 6505772Sas200622 mbind->service = msvc; 6515772Sas200622 mbind->instance_specific = 0; 6525772Sas200622 mxa->binding = mbind; 6535772Sas200622 654*7619SJose.Borrego@Sun.COM sec_addr = &mxa->send_hdr.alter_context_rsp_hdr.sec_addr; 6555772Sas200622 sec_addr->length = 0; 6565772Sas200622 bzero(sec_addr->port_spec, MLRPC_PORT_ANY_MAX_PORT_SPEC); 6575772Sas200622 6585772Sas200622 result->transfer_syntax = 6595772Sas200622 cont_list->p_cont_elem[0].transfer_syntaxes[0]; 6605772Sas200622 6615772Sas200622 return (MLRPC_DRC_BINDING_MADE); 6625772Sas200622 } 6635772Sas200622 6645772Sas200622 static int 6655772Sas200622 mlrpc_s_request(struct mlrpc_xaction *mxa) 6665772Sas200622 { 6675772Sas200622 struct mlrpc_binding *mbind; 6685772Sas200622 struct mlrpc_service *msvc; 6695772Sas200622 unsigned p_cont_id; 6705772Sas200622 int rc; 6715772Sas200622 6725772Sas200622 mxa->opnum = mxa->recv_hdr.request_hdr.opnum; 6735772Sas200622 p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id; 6745772Sas200622 6755772Sas200622 if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) == NULL) 6765772Sas200622 return (MLRPC_DRC_FAULT_REQUEST_PCONT_INVALID); 6775772Sas200622 6785772Sas200622 mxa->binding = mbind; 6795772Sas200622 msvc = mbind->service; 6805772Sas200622 6815772Sas200622 /* 6825772Sas200622 * Make room for the response hdr. 6835772Sas200622 */ 6845772Sas200622 mxa->send_mlnds.pdu_scan_offset = MLRPC_RSP_HDR_SIZE; 6855772Sas200622 6865772Sas200622 if (msvc->call_stub) 6875772Sas200622 rc = (*msvc->call_stub)(mxa); 6885772Sas200622 else 6895772Sas200622 rc = mlrpc_generic_call_stub(mxa); 6905772Sas200622 6915772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) { 6925772Sas200622 mlndo_printf(0, 0, "%s[0x%02x]: 0x%04x", 6935772Sas200622 msvc->name, mxa->opnum, rc); 6945772Sas200622 } 6955772Sas200622 6965772Sas200622 return (rc); 6975772Sas200622 } 6985772Sas200622 6995772Sas200622 /* 7005772Sas200622 * The transaction and the two mlnds streams use the same heap, which 7015772Sas200622 * should already exist at this point. The heap will also be available 7025772Sas200622 * to the stub. 7035772Sas200622 */ 7045772Sas200622 int 7055772Sas200622 mlrpc_generic_call_stub(struct mlrpc_xaction *mxa) 7065772Sas200622 { 7075772Sas200622 struct mlrpc_binding *mbind = mxa->binding; 7085772Sas200622 struct mlrpc_service *msvc = mbind->service; 7095772Sas200622 struct ndr_typeinfo *intf_ti = msvc->interface_ti; 7105772Sas200622 struct mlrpc_stub_table *ste; 7115772Sas200622 int opnum = mxa->opnum; 7125772Sas200622 unsigned p_len = intf_ti->c_size_fixed_part; 7135772Sas200622 char *param; 7145772Sas200622 int rc; 7155772Sas200622 7165772Sas200622 if (mxa->heap == NULL) { 7175772Sas200622 mlndo_printf(0, 0, "%s[0x%02x]: no heap", msvc->name, opnum); 7185772Sas200622 return (MLRPC_DRC_FAULT_OUT_OF_MEMORY); 7195772Sas200622 } 7205772Sas200622 7215772Sas200622 if ((ste = mlrpc_find_stub_in_svc(msvc, opnum)) == NULL) { 7225772Sas200622 mlndo_printf(0, 0, "%s[0x%02x]: invalid opnum", 7235772Sas200622 msvc->name, opnum); 7245772Sas200622 return (MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID); 7255772Sas200622 } 7265772Sas200622 7275772Sas200622 if ((param = mlrpc_heap_malloc(mxa->heap, p_len)) == NULL) 7285772Sas200622 return (MLRPC_DRC_FAULT_OUT_OF_MEMORY); 7295772Sas200622 7305772Sas200622 bzero(param, p_len); 7315772Sas200622 7325772Sas200622 rc = mlrpc_decode_call(mxa, param); 7335772Sas200622 if (!MLRPC_DRC_IS_OK(rc)) 7345772Sas200622 return (rc); 7355772Sas200622 7365772Sas200622 rc = (*ste->func)(param, mxa); 7375772Sas200622 if (rc == MLRPC_DRC_OK) 7385772Sas200622 rc = mlrpc_encode_return(mxa, param); 7395772Sas200622 7405772Sas200622 return (rc); 7415772Sas200622 } 7425772Sas200622 7435772Sas200622 /* 7445772Sas200622 * We can perform some initial setup of the response header here. 7455772Sas200622 * We also need to cache some of the information from the bind 7465772Sas200622 * negotiation for use during subsequent RPC calls. 7475772Sas200622 */ 7485772Sas200622 static void 7495772Sas200622 mlrpc_reply_prepare_hdr(struct mlrpc_xaction *mxa) 7505772Sas200622 { 751*7619SJose.Borrego@Sun.COM ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr; 752*7619SJose.Borrego@Sun.COM ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr; 7535772Sas200622 7545772Sas200622 hdr->rpc_vers = 5; 7555772Sas200622 hdr->rpc_vers_minor = 0; 7565772Sas200622 hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG + MLRPC_PFC_LAST_FRAG; 7575772Sas200622 hdr->packed_drep = rhdr->packed_drep; 7585772Sas200622 hdr->frag_length = 0; 7595772Sas200622 hdr->auth_length = 0; 7605772Sas200622 hdr->call_id = rhdr->call_id; 7615772Sas200622 #ifdef _BIG_ENDIAN 7625772Sas200622 hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII 7635772Sas200622 | MLRPC_REPLAB_INTG_BIG_ENDIAN; 7645772Sas200622 #else 7655772Sas200622 hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII 7665772Sas200622 | MLRPC_REPLAB_INTG_LITTLE_ENDIAN; 7675772Sas200622 #endif 7685772Sas200622 7695772Sas200622 switch (mxa->ptype) { 7705772Sas200622 case MLRPC_PTYPE_BIND: 7715772Sas200622 hdr->ptype = MLRPC_PTYPE_BIND_ACK; 7725772Sas200622 mxa->send_hdr.bind_ack_hdr.max_xmit_frag = 7735772Sas200622 mxa->recv_hdr.bind_hdr.max_xmit_frag; 7745772Sas200622 mxa->send_hdr.bind_ack_hdr.max_recv_frag = 7755772Sas200622 mxa->recv_hdr.bind_hdr.max_recv_frag; 7765772Sas200622 mxa->send_hdr.bind_ack_hdr.assoc_group_id = 7775772Sas200622 mxa->recv_hdr.bind_hdr.assoc_group_id; 7785772Sas200622 7795772Sas200622 if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0) 7805772Sas200622 mxa->send_hdr.bind_ack_hdr.assoc_group_id = time(0); 7815772Sas200622 7825772Sas200622 /* 7835772Sas200622 * Save the maximum fragment sizes 7845772Sas200622 * for use with subsequent requests. 7855772Sas200622 */ 7865772Sas200622 mxa->context->max_xmit_frag = 7875772Sas200622 mxa->recv_hdr.bind_hdr.max_xmit_frag; 7885772Sas200622 7895772Sas200622 mxa->context->max_recv_frag = 7905772Sas200622 mxa->recv_hdr.bind_hdr.max_recv_frag; 7915772Sas200622 7925772Sas200622 break; 7935772Sas200622 7945772Sas200622 case MLRPC_PTYPE_REQUEST: 7955772Sas200622 hdr->ptype = MLRPC_PTYPE_RESPONSE; 7965772Sas200622 /* mxa->send_hdr.response_hdr.alloc_hint */ 7975772Sas200622 mxa->send_hdr.response_hdr.p_cont_id = 7985772Sas200622 mxa->recv_hdr.request_hdr.p_cont_id; 7995772Sas200622 mxa->send_hdr.response_hdr.cancel_count = 0; 8005772Sas200622 mxa->send_hdr.response_hdr.reserved = 0; 8015772Sas200622 break; 8025772Sas200622 8035772Sas200622 case MLRPC_PTYPE_ALTER_CONTEXT: 8045772Sas200622 hdr->ptype = MLRPC_PTYPE_ALTER_CONTEXT_RESP; 8055772Sas200622 /* 806*7619SJose.Borrego@Sun.COM * The max_xmit_frag, max_recv_frag and assoc_group_id are 807*7619SJose.Borrego@Sun.COM * ignored by the client but it's useful to fill them in. 8085772Sas200622 */ 809*7619SJose.Borrego@Sun.COM mxa->send_hdr.alter_context_rsp_hdr.max_xmit_frag = 810*7619SJose.Borrego@Sun.COM mxa->recv_hdr.alter_context_hdr.max_xmit_frag; 811*7619SJose.Borrego@Sun.COM mxa->send_hdr.alter_context_rsp_hdr.max_recv_frag = 812*7619SJose.Borrego@Sun.COM mxa->recv_hdr.alter_context_hdr.max_recv_frag; 813*7619SJose.Borrego@Sun.COM mxa->send_hdr.alter_context_rsp_hdr.assoc_group_id = 814*7619SJose.Borrego@Sun.COM mxa->recv_hdr.alter_context_hdr.assoc_group_id; 8155772Sas200622 break; 8165772Sas200622 8175772Sas200622 default: 8185772Sas200622 hdr->ptype = 0xFF; 8195772Sas200622 } 8205772Sas200622 } 8215772Sas200622 8225772Sas200622 /* 8235772Sas200622 * Signal an RPC fault. The stream is reset and we overwrite whatever 8245772Sas200622 * was in the response header with the fault information. 8255772Sas200622 */ 8265772Sas200622 static void 8275772Sas200622 mlrpc_reply_fault(struct mlrpc_xaction *mxa, unsigned long drc) 8285772Sas200622 { 829*7619SJose.Borrego@Sun.COM ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr; 830*7619SJose.Borrego@Sun.COM ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr; 8315772Sas200622 struct mlndr_stream *mlnds = &mxa->send_mlnds; 8325772Sas200622 unsigned long fault_status; 8335772Sas200622 8345772Sas200622 MLNDS_RESET(mlnds); 8355772Sas200622 8365772Sas200622 hdr->rpc_vers = 5; 8375772Sas200622 hdr->rpc_vers_minor = 0; 8385772Sas200622 hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG + MLRPC_PFC_LAST_FRAG; 8395772Sas200622 hdr->packed_drep = rhdr->packed_drep; 8405772Sas200622 hdr->frag_length = sizeof (mxa->send_hdr.fault_hdr); 8415772Sas200622 hdr->auth_length = 0; 8425772Sas200622 hdr->call_id = rhdr->call_id; 8435772Sas200622 #ifdef _BIG_ENDIAN 8445772Sas200622 hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII 8455772Sas200622 | MLRPC_REPLAB_INTG_BIG_ENDIAN; 8465772Sas200622 #else 8475772Sas200622 hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII 8485772Sas200622 | MLRPC_REPLAB_INTG_LITTLE_ENDIAN; 8495772Sas200622 #endif 8505772Sas200622 8515772Sas200622 switch (drc & MLRPC_DRC_MASK_SPECIFIER) { 8525772Sas200622 case MLRPC_DRC_FAULT_OUT_OF_MEMORY: 8535772Sas200622 case MLRPC_DRC_FAULT_ENCODE_TOO_BIG: 8545772Sas200622 fault_status = MLRPC_FAULT_NCA_OUT_ARGS_TOO_BIG; 8555772Sas200622 break; 8565772Sas200622 8575772Sas200622 case MLRPC_DRC_FAULT_REQUEST_PCONT_INVALID: 8585772Sas200622 fault_status = MLRPC_FAULT_NCA_INVALID_PRES_CONTEXT_ID; 8595772Sas200622 break; 8605772Sas200622 8615772Sas200622 case MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID: 8625772Sas200622 fault_status = MLRPC_FAULT_NCA_OP_RNG_ERROR; 8635772Sas200622 break; 8645772Sas200622 8655772Sas200622 case MLRPC_DRC_FAULT_DECODE_FAILED: 8665772Sas200622 case MLRPC_DRC_FAULT_ENCODE_FAILED: 8675772Sas200622 fault_status = MLRPC_FAULT_NCA_PROTO_ERROR; 8685772Sas200622 break; 8695772Sas200622 8705772Sas200622 default: 8715772Sas200622 fault_status = MLRPC_FAULT_NCA_UNSPEC_REJECT; 8725772Sas200622 break; 8735772Sas200622 } 8745772Sas200622 8755772Sas200622 mxa->send_hdr.fault_hdr.common_hdr.ptype = MLRPC_PTYPE_FAULT; 8765772Sas200622 mxa->send_hdr.fault_hdr.status = fault_status; 8775772Sas200622 mxa->send_hdr.response_hdr.alloc_hint = hdr->frag_length; 8785772Sas200622 } 8795772Sas200622 880*7619SJose.Borrego@Sun.COM /* 881*7619SJose.Borrego@Sun.COM * Note that the frag_length for bind ack and alter context is 882*7619SJose.Borrego@Sun.COM * non-standard. 883*7619SJose.Borrego@Sun.COM */ 8845772Sas200622 static int 8855772Sas200622 mlrpc_build_reply(struct mlrpc_xaction *mxa) 8865772Sas200622 { 887*7619SJose.Borrego@Sun.COM ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr; 8885772Sas200622 struct mlndr_stream *mlnds = &mxa->send_mlnds; 8896482Samw uint8_t *pdu_buf; 8905772Sas200622 unsigned long pdu_size; 8915772Sas200622 unsigned long frag_size; 8925772Sas200622 unsigned long pdu_data_size; 8935772Sas200622 unsigned long frag_data_size; 8945772Sas200622 8955772Sas200622 frag_size = mlrpc_frag_size; 8965772Sas200622 pdu_size = mlnds->pdu_size; 8976482Samw pdu_buf = mlnds->pdu_base_addr; 8985772Sas200622 8995772Sas200622 if (pdu_size <= frag_size) { 9005772Sas200622 /* 9015772Sas200622 * Single fragment response. The PDU size may be zero 9025772Sas200622 * here (i.e. bind or fault response). So don't make 9035772Sas200622 * any assumptions about it until after the header is 9045772Sas200622 * encoded. 9055772Sas200622 */ 9065772Sas200622 switch (hdr->ptype) { 9075772Sas200622 case MLRPC_PTYPE_BIND_ACK: 908*7619SJose.Borrego@Sun.COM hdr->frag_length = mlrpc_bind_ack_hdr_size(mxa); 9095772Sas200622 break; 9105772Sas200622 9115772Sas200622 case MLRPC_PTYPE_FAULT: 9125772Sas200622 /* already setup */ 9135772Sas200622 break; 9145772Sas200622 9155772Sas200622 case MLRPC_PTYPE_RESPONSE: 9165772Sas200622 hdr->frag_length = pdu_size; 9175772Sas200622 mxa->send_hdr.response_hdr.alloc_hint = 9185772Sas200622 hdr->frag_length; 9195772Sas200622 break; 9205772Sas200622 921*7619SJose.Borrego@Sun.COM case MLRPC_PTYPE_ALTER_CONTEXT_RESP: 922*7619SJose.Borrego@Sun.COM hdr->frag_length = mlrpc_alter_context_rsp_hdr_size(); 923*7619SJose.Borrego@Sun.COM break; 924*7619SJose.Borrego@Sun.COM 9255772Sas200622 default: 9265772Sas200622 hdr->frag_length = pdu_size; 9275772Sas200622 break; 9285772Sas200622 } 9295772Sas200622 9305772Sas200622 mlnds->pdu_scan_offset = 0; 9315772Sas200622 (void) mlrpc_encode_pdu_hdr(mxa); 9326482Samw pdu_size = mlnds->pdu_size; 9336482Samw mlrpc_build_frag(mlnds, pdu_buf, pdu_size); 9345772Sas200622 return (0); 9355772Sas200622 } 9365772Sas200622 9375772Sas200622 /* 9385772Sas200622 * Multiple fragment response. 9395772Sas200622 */ 9405772Sas200622 hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG; 9415772Sas200622 hdr->frag_length = frag_size; 9425772Sas200622 mxa->send_hdr.response_hdr.alloc_hint = pdu_size - MLRPC_RSP_HDR_SIZE; 9435772Sas200622 mlnds->pdu_scan_offset = 0; 9445772Sas200622 (void) mlrpc_encode_pdu_hdr(mxa); 9456482Samw mlrpc_build_frag(mlnds, pdu_buf, frag_size); 9465772Sas200622 9475772Sas200622 /* 9485772Sas200622 * We need to update the 24-byte header in subsequent fragments. 9495772Sas200622 * 9506482Samw * pdu_data_size: total data remaining to be handled 9516482Samw * frag_size: total fragment size including header 9526482Samw * frag_data_size: data in fragment 9535772Sas200622 * (i.e. frag_size - MLRPC_RSP_HDR_SIZE) 9545772Sas200622 */ 9555772Sas200622 pdu_data_size = pdu_size - MLRPC_RSP_HDR_SIZE; 9565772Sas200622 frag_data_size = frag_size - MLRPC_RSP_HDR_SIZE; 9575772Sas200622 9586482Samw while (pdu_data_size) { 9596482Samw mxa->send_hdr.response_hdr.alloc_hint -= frag_data_size; 9606482Samw pdu_data_size -= frag_data_size; 9616482Samw pdu_buf += frag_data_size; 9625772Sas200622 9636482Samw if (pdu_data_size <= frag_data_size) { 9646482Samw frag_data_size = pdu_data_size; 9656482Samw frag_size = frag_data_size + MLRPC_RSP_HDR_SIZE; 9666482Samw hdr->pfc_flags = MLRPC_PFC_LAST_FRAG; 9675772Sas200622 } else { 9686482Samw hdr->pfc_flags = 0; 9695772Sas200622 } 9705772Sas200622 9716482Samw hdr->frag_length = frag_size; 9726482Samw mlnds->pdu_scan_offset = 0; 9736483Samw (void) mlrpc_encode_pdu_hdr(mxa); 9746482Samw bcopy(mlnds->pdu_base_addr, pdu_buf, MLRPC_RSP_HDR_SIZE); 9755772Sas200622 9766482Samw mlrpc_build_frag(mlnds, pdu_buf, frag_size); 9775772Sas200622 9786482Samw if (hdr->pfc_flags & MLRPC_PFC_LAST_FRAG) 9796482Samw break; 9805772Sas200622 } 9815772Sas200622 9825772Sas200622 return (0); 9835772Sas200622 } 9846482Samw 9856482Samw /* 9866482Samw * mlrpc_build_frag 9876482Samw * 9886482Samw * Build an RPC PDU fragment from the specified buffer. 9896482Samw * If malloc fails, the client will see a header/pdu inconsistency 9906482Samw * and report an error. 9916482Samw */ 9926482Samw static void 9936482Samw mlrpc_build_frag(struct mlndr_stream *mlnds, uint8_t *buf, uint32_t len) 9946482Samw { 9956482Samw ndr_frag_t *frag; 9966482Samw int size = sizeof (ndr_frag_t) + len; 9976482Samw 9986482Samw if ((frag = (ndr_frag_t *)malloc(size)) == NULL) 9996482Samw return; 10006482Samw 10016482Samw frag->next = NULL; 10026482Samw frag->buf = (uint8_t *)frag + sizeof (ndr_frag_t); 10036482Samw frag->len = len; 10046482Samw bcopy(buf, frag->buf, len); 10056482Samw 10067052Samw if (mlnds->frags.head == NULL) { 10077052Samw mlnds->frags.head = frag; 10087052Samw mlnds->frags.tail = frag; 10097052Samw mlnds->frags.nfrag = 1; 10106482Samw } else { 10117052Samw mlnds->frags.tail->next = frag; 10127052Samw mlnds->frags.tail = frag; 10137052Samw ++mlnds->frags.nfrag; 10146482Samw } 10156482Samw } 1016