1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Server side RPC handler. 30 */ 31 32 #include <sys/byteorder.h> 33 #include <thread.h> 34 #include <synch.h> 35 #include <stdlib.h> 36 #include <strings.h> 37 #include <string.h> 38 #include <time.h> 39 40 #include <smbsrv/libsmb.h> 41 #include <smbsrv/libmlrpc.h> 42 #include <smbsrv/mlsvc.h> 43 #include <smbsrv/ndr.h> 44 #include <smbsrv/mlrpc.h> 45 #include <smbsrv/mlsvc_util.h> 46 #include <smbsrv/ntsid.h> 47 #include <smbsrv/smb_winpipe.h> 48 49 /* 50 * Fragment size (5680: NT style). 51 */ 52 #define MLRPC_FRAG_SZ 5680 53 static unsigned long mlrpc_frag_size = MLRPC_FRAG_SZ; 54 55 /* 56 * Context table. 57 */ 58 #define CTXT_TABLE_ENTRIES 128 59 static struct mlsvc_rpc_context context_table[CTXT_TABLE_ENTRIES]; 60 static mutex_t mlrpc_context_lock; 61 62 static int mlrpc_s_process(struct mlrpc_xaction *); 63 static int mlrpc_s_bind(struct mlrpc_xaction *); 64 static int mlrpc_s_request(struct mlrpc_xaction *); 65 static void mlrpc_reply_prepare_hdr(struct mlrpc_xaction *); 66 static int mlrpc_s_alter_context(struct mlrpc_xaction *); 67 static void mlrpc_reply_bind_ack(struct mlrpc_xaction *); 68 static void mlrpc_reply_fault(struct mlrpc_xaction *, unsigned long); 69 static int mlrpc_build_reply(struct mlrpc_xaction *); 70 71 /* 72 * This is the RPC service server-side entry point. All MSRPC encoded 73 * messages should be passed through here. We use the same context 74 * structure as the client side but we don't need to set up the client 75 * side info. 76 */ 77 struct mlsvc_rpc_context * 78 mlrpc_process(int fid, smb_dr_user_ctx_t *user_ctx) 79 { 80 struct mlsvc_rpc_context *context; 81 struct mlrpc_xaction *mxa; 82 struct mlndr_stream *recv_mlnds; 83 struct mlndr_stream *send_mlnds; 84 unsigned char *pdu_base_addr; 85 char *data; 86 int datalen; 87 88 if ((context = mlrpc_lookup(fid)) == NULL) 89 return (NULL); 90 91 context->user_ctx = user_ctx; 92 data = context->inpipe->sp_data; 93 datalen = context->inpipe->sp_datalen; 94 95 mxa = (struct mlrpc_xaction *)malloc(sizeof (struct mlrpc_xaction)); 96 if (mxa == NULL) 97 return (NULL); 98 99 bzero(mxa, sizeof (struct mlrpc_xaction)); 100 mxa->fid = fid; 101 mxa->context = context; 102 mxa->binding_list = context->binding; 103 104 if ((mxa->heap = mlrpc_heap_create()) == NULL) { 105 free(mxa); 106 return (NULL); 107 } 108 109 recv_mlnds = &mxa->recv_mlnds; 110 (void) mlnds_initialize(recv_mlnds, datalen, NDR_MODE_CALL_RECV, 111 mxa->heap); 112 113 bcopy(data, recv_mlnds->pdu_base_addr, datalen); 114 115 send_mlnds = &mxa->send_mlnds; 116 (void) mlnds_initialize(send_mlnds, 0, NDR_MODE_RETURN_SEND, mxa->heap); 117 118 (void) mlrpc_s_process(mxa); 119 120 /* 121 * Different pointers for single frag vs multi frag responses. 122 */ 123 if (send_mlnds->pdu_base_addr_with_rpc_hdrs) 124 pdu_base_addr = send_mlnds->pdu_base_addr_with_rpc_hdrs; 125 else 126 pdu_base_addr = send_mlnds->pdu_base_addr; 127 128 datalen = send_mlnds->pdu_size_with_rpc_hdrs; 129 context->outpipe->sp_datalen = datalen; 130 bcopy(pdu_base_addr, context->outpipe->sp_data, datalen); 131 132 mlnds_destruct(&mxa->recv_mlnds); 133 mlnds_destruct(&mxa->send_mlnds); 134 mlrpc_heap_destroy(mxa->heap); 135 free(mxa); 136 return (context); 137 } 138 139 /* 140 * Lookup the context for pipeid. If one exists, return a pointer to it. 141 * Otherwise attempt to allocate a new context and return it. If the 142 * context table is full, return a null pointer. 143 */ 144 struct mlsvc_rpc_context * 145 mlrpc_lookup(int fid) 146 { 147 struct mlsvc_rpc_context *context; 148 struct mlsvc_rpc_context *available = NULL; 149 int i; 150 151 (void) mutex_lock(&mlrpc_context_lock); 152 153 for (i = 0; i < CTXT_TABLE_ENTRIES; ++i) { 154 context = &context_table[i]; 155 156 if (available == NULL && context->fid == 0) { 157 available = context; 158 continue; 159 } 160 161 if (context->fid == fid) { 162 (void) mutex_unlock(&mlrpc_context_lock); 163 return (context); 164 } 165 } 166 167 if (available) { 168 bzero(available, sizeof (struct mlsvc_rpc_context)); 169 available->inpipe = malloc(SMB_CTXT_PIPE_SZ); 170 available->outpipe = malloc(SMB_CTXT_PIPE_SZ); 171 172 if (available->inpipe == NULL || available->outpipe == NULL) { 173 free(available->inpipe); 174 free(available->outpipe); 175 bzero(available, sizeof (struct mlsvc_rpc_context)); 176 (void) mutex_unlock(&mlrpc_context_lock); 177 return (NULL); 178 } 179 180 bzero(available->inpipe, sizeof (smb_pipe_t)); 181 bzero(available->outpipe, sizeof (smb_pipe_t)); 182 available->fid = fid; 183 available->inpipe->sp_pipeid = fid; 184 available->outpipe->sp_pipeid = fid; 185 186 mlrpc_binding_pool_initialize(&available->binding, 187 available->binding_pool, CTXT_N_BINDING_POOL); 188 } 189 190 (void) mutex_unlock(&mlrpc_context_lock); 191 return (available); 192 } 193 194 /* 195 * This function should be called to release the context associated 196 * with a fid when the client performs a close file. 197 */ 198 void 199 mlrpc_release(int fid) 200 { 201 struct mlsvc_rpc_context *context; 202 int i; 203 204 (void) mutex_lock(&mlrpc_context_lock); 205 206 for (i = 0; i < CTXT_TABLE_ENTRIES; ++i) { 207 context = &context_table[i]; 208 209 if (context->fid == fid) { 210 ndr_hdclose(fid); 211 free(context->inpipe); 212 free(context->outpipe); 213 bzero(context, sizeof (struct mlsvc_rpc_context)); 214 break; 215 } 216 } 217 218 (void) mutex_unlock(&mlrpc_context_lock); 219 } 220 221 /* 222 * This is the entry point for all server-side RPC processing. 223 * It is assumed that the PDU has already been received. 224 */ 225 static int 226 mlrpc_s_process(struct mlrpc_xaction *mxa) 227 { 228 int rc; 229 230 rc = mlrpc_decode_pdu_hdr(mxa); 231 if (!MLRPC_DRC_IS_OK(rc)) 232 return (-1); 233 234 (void) mlrpc_reply_prepare_hdr(mxa); 235 236 switch (mxa->ptype) { 237 case MLRPC_PTYPE_BIND: 238 rc = mlrpc_s_bind(mxa); 239 break; 240 241 case MLRPC_PTYPE_REQUEST: 242 rc = mlrpc_s_request(mxa); 243 break; 244 245 case MLRPC_PTYPE_ALTER_CONTEXT: 246 rc = mlrpc_s_alter_context(mxa); 247 break; 248 249 default: 250 rc = MLRPC_DRC_FAULT_RPCHDR_PTYPE_INVALID; 251 break; 252 } 253 254 if (MLRPC_DRC_IS_FAULT(rc)) 255 mlrpc_reply_fault(mxa, rc); 256 257 (void) mlrpc_build_reply(mxa); 258 return (rc); 259 } 260 261 /* 262 * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple 263 * p_results[] not supported. 264 */ 265 static int 266 mlrpc_s_bind(struct mlrpc_xaction *mxa) 267 { 268 mlrpc_p_cont_list_t *cont_list; 269 mlrpc_p_result_list_t *result_list; 270 mlrpc_p_result_t *result; 271 unsigned p_cont_id; 272 struct mlrpc_binding *mbind; 273 ndr_uuid_t *as_uuid; 274 ndr_uuid_t *ts_uuid; 275 char as_buf[64]; 276 char ts_buf[64]; 277 int as_vers; 278 int ts_vers; 279 struct mlndr_stream *send_mlnds; 280 struct mlrpc_service *msvc; 281 int rc; 282 mlrpc_port_any_t *sec_addr; 283 284 /* acquire targets */ 285 cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem; 286 result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list; 287 result = &result_list->p_results[0]; 288 289 /* 290 * Set up temporary secondary address port. 291 * We will correct this later (below). 292 */ 293 send_mlnds = &mxa->send_mlnds; 294 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 295 sec_addr->length = 13; 296 (void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs"); 297 298 result_list->n_results = 1; 299 result_list->reserved = 0; 300 result_list->reserved2 = 0; 301 result->result = MLRPC_PCDR_ACCEPTANCE; 302 result->reason = 0; 303 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax)); 304 305 /* sanity check */ 306 if (cont_list->n_context_elem != 1 || 307 cont_list->p_cont_elem[0].n_transfer_syn != 1) { 308 mlndo_trace("mlrpc_s_bind: warning: multiple p_cont_elem"); 309 } 310 311 p_cont_id = cont_list->p_cont_elem[0].p_cont_id; 312 313 if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) != NULL) { 314 /* 315 * Duplicate p_cont_id. 316 * Send a bind_ack with a better error. 317 */ 318 mlndo_trace("mlrpc_s_bind: duplicate binding"); 319 return (MLRPC_DRC_FAULT_BIND_PCONT_BUSY); 320 } 321 322 if ((mbind = mlrpc_new_binding(mxa)) == NULL) { 323 /* 324 * No free binding slot 325 */ 326 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 327 result->reason = MLRPC_PPR_LOCAL_LIMIT_EXCEEDED; 328 mlndo_trace("mlrpc_s_bind: no resources"); 329 return (MLRPC_DRC_OK); 330 } 331 332 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid; 333 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version; 334 335 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid; 336 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version; 337 338 msvc = mlrpc_find_service_by_uuids(as_uuid, as_vers, ts_uuid, ts_vers); 339 if (!msvc) { 340 mlrpc_uuid_to_str(as_uuid, as_buf); 341 mlrpc_uuid_to_str(ts_uuid, ts_buf); 342 343 mlndo_printf(send_mlnds, 0, "mlrpc_s_bind: unknown service"); 344 mlndo_printf(send_mlnds, 0, "abs=%s v%d, xfer=%s v%d", 345 as_buf, as_vers, ts_buf, ts_vers); 346 347 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 348 result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 349 return (MLRPC_DRC_OK); 350 } 351 352 /* 353 * We can now use the correct secondary address port. 354 */ 355 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 356 sec_addr->length = strlen(msvc->sec_addr_port) + 1; 357 (void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port, 358 MLRPC_PORT_ANY_MAX_PORT_SPEC); 359 360 mbind->p_cont_id = p_cont_id; 361 mbind->which_side = MLRPC_BIND_SIDE_SERVER; 362 /* mbind->context set by app */ 363 mbind->service = msvc; 364 mbind->instance_specific = 0; 365 366 mxa->binding = mbind; 367 368 if (msvc->bind_req) { 369 /* 370 * Call the service-specific bind() handler. If 371 * this fails, we shouild send a specific error 372 * on the bind ack. 373 */ 374 rc = (msvc->bind_req)(mxa); 375 if (MLRPC_DRC_IS_FAULT(rc)) { 376 mbind->service = 0; /* free binding slot */ 377 mbind->which_side = 0; 378 mbind->p_cont_id = 0; 379 mbind->instance_specific = 0; 380 return (rc); 381 } 382 } 383 384 result->transfer_syntax = 385 cont_list->p_cont_elem[0].transfer_syntaxes[0]; 386 387 /* 388 * Special rejection of Windows 2000 DSSETUP interface. 389 * This interface was introduced in Windows 2000 but has 390 * been subsequently deprecated due to problems. 391 */ 392 if (strcmp(msvc->name, "DSSETUP") == 0) { 393 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 394 result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 395 } 396 397 return (MLRPC_DRC_BINDING_MADE); 398 } 399 400 /* 401 * mlrpc_s_alter_context 402 * 403 * The alter context request is used to request additional presentation 404 * context for another interface and/or version. It's very similar to a 405 * bind request. 406 * 407 * We don't fully support multiple contexts so, for now, we reject this 408 * request. Windows 2000 clients attempt to use an alternate LSA context 409 * when ACLs are modified. 410 */ 411 static int 412 mlrpc_s_alter_context(struct mlrpc_xaction *mxa) 413 { 414 mlrpc_p_result_list_t *result_list; 415 mlrpc_p_result_t *result; 416 mlrpc_p_cont_list_t *cont_list; 417 struct mlrpc_binding *mbind; 418 struct mlrpc_service *msvc; 419 unsigned p_cont_id; 420 ndr_uuid_t *as_uuid; 421 ndr_uuid_t *ts_uuid; 422 int as_vers; 423 int ts_vers; 424 mlrpc_port_any_t *sec_addr; 425 426 result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list; 427 result_list->n_results = 1; 428 result_list->reserved = 0; 429 result_list->reserved2 = 0; 430 431 result = &result_list->p_results[0]; 432 result->result = MLRPC_PCDR_ACCEPTANCE; 433 result->reason = 0; 434 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax)); 435 436 if (mxa != NULL) { 437 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 438 result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 439 return (MLRPC_DRC_OK); 440 } 441 442 cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem; 443 p_cont_id = cont_list->p_cont_elem[0].p_cont_id; 444 445 if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) != NULL) 446 return (MLRPC_DRC_FAULT_BIND_PCONT_BUSY); 447 448 if ((mbind = mlrpc_new_binding(mxa)) == NULL) { 449 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 450 result->reason = MLRPC_PPR_LOCAL_LIMIT_EXCEEDED; 451 return (MLRPC_DRC_OK); 452 } 453 454 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid; 455 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version; 456 457 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid; 458 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version; 459 460 msvc = mlrpc_find_service_by_uuids(as_uuid, as_vers, ts_uuid, ts_vers); 461 if (msvc == 0) { 462 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 463 result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 464 return (MLRPC_DRC_OK); 465 } 466 467 mbind->p_cont_id = p_cont_id; 468 mbind->which_side = MLRPC_BIND_SIDE_SERVER; 469 /* mbind->context set by app */ 470 mbind->service = msvc; 471 mbind->instance_specific = 0; 472 mxa->binding = mbind; 473 474 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 475 sec_addr->length = 0; 476 bzero(sec_addr->port_spec, MLRPC_PORT_ANY_MAX_PORT_SPEC); 477 478 result->transfer_syntax = 479 cont_list->p_cont_elem[0].transfer_syntaxes[0]; 480 481 return (MLRPC_DRC_BINDING_MADE); 482 } 483 484 static int 485 mlrpc_s_request(struct mlrpc_xaction *mxa) 486 { 487 struct mlrpc_binding *mbind; 488 struct mlrpc_service *msvc; 489 unsigned p_cont_id; 490 int rc; 491 492 mxa->opnum = mxa->recv_hdr.request_hdr.opnum; 493 p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id; 494 495 if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) == NULL) 496 return (MLRPC_DRC_FAULT_REQUEST_PCONT_INVALID); 497 498 mxa->binding = mbind; 499 msvc = mbind->service; 500 501 /* 502 * Make room for the response hdr. 503 */ 504 mxa->send_mlnds.pdu_scan_offset = MLRPC_RSP_HDR_SIZE; 505 506 if (msvc->call_stub) 507 rc = (*msvc->call_stub)(mxa); 508 else 509 rc = mlrpc_generic_call_stub(mxa); 510 511 if (MLRPC_DRC_IS_FAULT(rc)) { 512 mlndo_printf(0, 0, "%s[0x%02x]: 0x%04x", 513 msvc->name, mxa->opnum, rc); 514 } 515 516 return (rc); 517 } 518 519 /* 520 * The transaction and the two mlnds streams use the same heap, which 521 * should already exist at this point. The heap will also be available 522 * to the stub. 523 */ 524 int 525 mlrpc_generic_call_stub(struct mlrpc_xaction *mxa) 526 { 527 struct mlrpc_binding *mbind = mxa->binding; 528 struct mlrpc_service *msvc = mbind->service; 529 struct ndr_typeinfo *intf_ti = msvc->interface_ti; 530 struct mlrpc_stub_table *ste; 531 int opnum = mxa->opnum; 532 unsigned p_len = intf_ti->c_size_fixed_part; 533 char *param; 534 int rc; 535 536 if (mxa->heap == NULL) { 537 mlndo_printf(0, 0, "%s[0x%02x]: no heap", msvc->name, opnum); 538 return (MLRPC_DRC_FAULT_OUT_OF_MEMORY); 539 } 540 541 if ((ste = mlrpc_find_stub_in_svc(msvc, opnum)) == NULL) { 542 mlndo_printf(0, 0, "%s[0x%02x]: invalid opnum", 543 msvc->name, opnum); 544 return (MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID); 545 } 546 547 if ((param = mlrpc_heap_malloc(mxa->heap, p_len)) == NULL) 548 return (MLRPC_DRC_FAULT_OUT_OF_MEMORY); 549 550 bzero(param, p_len); 551 552 rc = mlrpc_decode_call(mxa, param); 553 if (!MLRPC_DRC_IS_OK(rc)) 554 return (rc); 555 556 rc = (*ste->func)(param, mxa); 557 if (rc == MLRPC_DRC_OK) 558 rc = mlrpc_encode_return(mxa, param); 559 560 return (rc); 561 } 562 563 /* 564 * We can perform some initial setup of the response header here. 565 * We also need to cache some of the information from the bind 566 * negotiation for use during subsequent RPC calls. 567 */ 568 static void 569 mlrpc_reply_prepare_hdr(struct mlrpc_xaction *mxa) 570 { 571 mlrpcconn_common_header_t *rhdr = &mxa->recv_hdr.common_hdr; 572 mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr; 573 574 hdr->rpc_vers = 5; 575 hdr->rpc_vers_minor = 0; 576 hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG + MLRPC_PFC_LAST_FRAG; 577 hdr->packed_drep = rhdr->packed_drep; 578 hdr->frag_length = 0; 579 hdr->auth_length = 0; 580 hdr->call_id = rhdr->call_id; 581 #ifdef _BIG_ENDIAN 582 hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII 583 | MLRPC_REPLAB_INTG_BIG_ENDIAN; 584 #else 585 hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII 586 | MLRPC_REPLAB_INTG_LITTLE_ENDIAN; 587 #endif 588 589 switch (mxa->ptype) { 590 case MLRPC_PTYPE_BIND: 591 hdr->ptype = MLRPC_PTYPE_BIND_ACK; 592 mxa->send_hdr.bind_ack_hdr.max_xmit_frag = 593 mxa->recv_hdr.bind_hdr.max_xmit_frag; 594 mxa->send_hdr.bind_ack_hdr.max_recv_frag = 595 mxa->recv_hdr.bind_hdr.max_recv_frag; 596 mxa->send_hdr.bind_ack_hdr.assoc_group_id = 597 mxa->recv_hdr.bind_hdr.assoc_group_id; 598 599 if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0) 600 mxa->send_hdr.bind_ack_hdr.assoc_group_id = time(0); 601 602 /* 603 * Save the maximum fragment sizes 604 * for use with subsequent requests. 605 */ 606 mxa->context->max_xmit_frag = 607 mxa->recv_hdr.bind_hdr.max_xmit_frag; 608 609 mxa->context->max_recv_frag = 610 mxa->recv_hdr.bind_hdr.max_recv_frag; 611 612 break; 613 614 case MLRPC_PTYPE_REQUEST: 615 hdr->ptype = MLRPC_PTYPE_RESPONSE; 616 /* mxa->send_hdr.response_hdr.alloc_hint */ 617 mxa->send_hdr.response_hdr.p_cont_id = 618 mxa->recv_hdr.request_hdr.p_cont_id; 619 mxa->send_hdr.response_hdr.cancel_count = 0; 620 mxa->send_hdr.response_hdr.reserved = 0; 621 break; 622 623 case MLRPC_PTYPE_ALTER_CONTEXT: 624 hdr->ptype = MLRPC_PTYPE_ALTER_CONTEXT_RESP; 625 /* 626 * The max_xmit_frag, max_recv_frag 627 * and assoc_group_id are ignored. 628 */ 629 break; 630 631 default: 632 hdr->ptype = 0xFF; 633 } 634 } 635 636 /* 637 * Finish and encode the bind acknowledge (MLRPC_PTYPE_BIND_ACK) header. 638 * The frag_length is different from a regular RPC response. 639 */ 640 static void 641 mlrpc_reply_bind_ack(struct mlrpc_xaction *mxa) 642 { 643 mlrpcconn_common_header_t *hdr; 644 mlrpcconn_bind_ack_hdr_t *bahdr; 645 646 hdr = &mxa->send_hdr.common_hdr; 647 bahdr = &mxa->send_hdr.bind_ack_hdr; 648 hdr->frag_length = mlrpc_bind_ack_hdr_size(bahdr); 649 } 650 651 /* 652 * Signal an RPC fault. The stream is reset and we overwrite whatever 653 * was in the response header with the fault information. 654 */ 655 static void 656 mlrpc_reply_fault(struct mlrpc_xaction *mxa, unsigned long drc) 657 { 658 mlrpcconn_common_header_t *rhdr = &mxa->recv_hdr.common_hdr; 659 mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr; 660 struct mlndr_stream *mlnds = &mxa->send_mlnds; 661 unsigned long fault_status; 662 663 MLNDS_RESET(mlnds); 664 665 hdr->rpc_vers = 5; 666 hdr->rpc_vers_minor = 0; 667 hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG + MLRPC_PFC_LAST_FRAG; 668 hdr->packed_drep = rhdr->packed_drep; 669 hdr->frag_length = sizeof (mxa->send_hdr.fault_hdr); 670 hdr->auth_length = 0; 671 hdr->call_id = rhdr->call_id; 672 #ifdef _BIG_ENDIAN 673 hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII 674 | MLRPC_REPLAB_INTG_BIG_ENDIAN; 675 #else 676 hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII 677 | MLRPC_REPLAB_INTG_LITTLE_ENDIAN; 678 #endif 679 680 switch (drc & MLRPC_DRC_MASK_SPECIFIER) { 681 case MLRPC_DRC_FAULT_OUT_OF_MEMORY: 682 case MLRPC_DRC_FAULT_ENCODE_TOO_BIG: 683 fault_status = MLRPC_FAULT_NCA_OUT_ARGS_TOO_BIG; 684 break; 685 686 case MLRPC_DRC_FAULT_REQUEST_PCONT_INVALID: 687 fault_status = MLRPC_FAULT_NCA_INVALID_PRES_CONTEXT_ID; 688 break; 689 690 case MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID: 691 fault_status = MLRPC_FAULT_NCA_OP_RNG_ERROR; 692 break; 693 694 case MLRPC_DRC_FAULT_DECODE_FAILED: 695 case MLRPC_DRC_FAULT_ENCODE_FAILED: 696 fault_status = MLRPC_FAULT_NCA_PROTO_ERROR; 697 break; 698 699 default: 700 fault_status = MLRPC_FAULT_NCA_UNSPEC_REJECT; 701 break; 702 } 703 704 mxa->send_hdr.fault_hdr.common_hdr.ptype = MLRPC_PTYPE_FAULT; 705 mxa->send_hdr.fault_hdr.status = fault_status; 706 mxa->send_hdr.response_hdr.alloc_hint = hdr->frag_length; 707 } 708 709 static int 710 mlrpc_build_reply(struct mlrpc_xaction *mxa) 711 { 712 mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr; 713 struct mlndr_stream *mlnds = &mxa->send_mlnds; 714 unsigned long pdu_size; 715 unsigned long frag_size; 716 unsigned long pdu_data_size; 717 unsigned long frag_data_size; 718 uint32_t rem_dlen; 719 uint32_t save_rem_dlen; 720 uint32_t bytesoff; 721 uint32_t cnt; 722 uint32_t obytes; 723 uint32_t num_ext_frags; 724 uint16_t last_frag = 0; 725 uchar_t *frag_startp; 726 mlrpcconn_common_header_t *rpc_hdr; 727 728 hdr = &mxa->send_hdr.common_hdr; 729 730 frag_size = mlrpc_frag_size; 731 pdu_size = mlnds->pdu_size; 732 733 if (pdu_size <= frag_size) { 734 /* 735 * Single fragment response. The PDU size may be zero 736 * here (i.e. bind or fault response). So don't make 737 * any assumptions about it until after the header is 738 * encoded. 739 */ 740 switch (hdr->ptype) { 741 case MLRPC_PTYPE_BIND_ACK: 742 mlrpc_reply_bind_ack(mxa); 743 break; 744 745 case MLRPC_PTYPE_FAULT: 746 /* already setup */ 747 break; 748 749 case MLRPC_PTYPE_RESPONSE: 750 hdr->frag_length = pdu_size; 751 mxa->send_hdr.response_hdr.alloc_hint = 752 hdr->frag_length; 753 break; 754 755 default: 756 hdr->frag_length = pdu_size; 757 break; 758 } 759 760 mlnds->pdu_scan_offset = 0; 761 (void) mlrpc_encode_pdu_hdr(mxa); 762 763 mlnds->pdu_size_with_rpc_hdrs = mlnds->pdu_size; 764 mlnds->pdu_base_addr_with_rpc_hdrs = 0; 765 return (0); 766 } 767 768 /* 769 * Multiple fragment response. 770 */ 771 hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG; 772 hdr->frag_length = frag_size; 773 mxa->send_hdr.response_hdr.alloc_hint = pdu_size - MLRPC_RSP_HDR_SIZE; 774 mlnds->pdu_scan_offset = 0; 775 776 (void) mlrpc_encode_pdu_hdr(mxa); 777 778 /* 779 * We need to update the 24-byte header in subsequent fragments. 780 * 781 * pdu_data_size: total data remaining to be handled 782 * frag_size: total fragment size including header 783 * frag_data_size: data in fragment 784 * (i.e. frag_size - MLRPC_RSP_HDR_SIZE) 785 */ 786 pdu_data_size = pdu_size - MLRPC_RSP_HDR_SIZE; 787 frag_data_size = frag_size - MLRPC_RSP_HDR_SIZE; 788 789 num_ext_frags = pdu_data_size / frag_data_size; 790 791 /* 792 * We may need to stretch the pipe and insert an RPC header 793 * at each frag boundary. The response will get chunked into 794 * xdrlen sizes for each trans request. 795 */ 796 mlnds->pdu_base_addr_with_rpc_hdrs 797 = malloc(pdu_size + (num_ext_frags * MLRPC_RSP_HDR_SIZE)); 798 mlnds->pdu_size_with_rpc_hdrs = 799 mlnds->pdu_size + (num_ext_frags * MLRPC_RSP_HDR_SIZE); 800 801 /* 802 * Start stretching loop. 803 */ 804 bcopy(mlnds->pdu_base_addr, 805 mlnds->pdu_base_addr_with_rpc_hdrs, frag_size); 806 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 807 rpc_hdr = (mlrpcconn_common_header_t *) 808 mlnds->pdu_base_addr_with_rpc_hdrs; 809 rpc_hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG; 810 rem_dlen = pdu_data_size - frag_size; 811 bytesoff = frag_size; 812 cnt = 1; 813 while (num_ext_frags--) { 814 /* first copy the RPC header to the front of the frag */ 815 bcopy(mlnds->pdu_base_addr, mlnds->pdu_base_addr_with_rpc_hdrs + 816 (cnt * frag_size), MLRPC_RSP_HDR_SIZE); 817 818 /* then copy the data portion of the frag */ 819 save_rem_dlen = rem_dlen; 820 if (rem_dlen >= (frag_size - MLRPC_RSP_HDR_SIZE)) { 821 rem_dlen = rem_dlen - frag_size + MLRPC_RSP_HDR_SIZE; 822 obytes = frag_size - MLRPC_RSP_HDR_SIZE; 823 } else { 824 last_frag = 1; /* this is the last one */ 825 obytes = rem_dlen; 826 } 827 828 frag_startp = mlnds->pdu_base_addr_with_rpc_hdrs + 829 (cnt * frag_size); 830 bcopy(mlnds->pdu_base_addr + bytesoff, 831 frag_startp + MLRPC_RSP_HDR_SIZE, obytes); 832 833 /* set the FRAG FLAGS in the frag header spot */ 834 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 835 rpc_hdr = (mlrpcconn_common_header_t *)frag_startp; 836 if (last_frag) { 837 rpc_hdr->frag_length = save_rem_dlen; 838 rpc_hdr->pfc_flags = MLRPC_PFC_LAST_FRAG; 839 } else { 840 rpc_hdr->pfc_flags = 0; 841 } 842 843 bytesoff += (frag_size - MLRPC_RSP_HDR_SIZE); 844 cnt++; 845 } 846 847 return (0); 848 } 849