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