Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

lpcsend.c File Reference

#include "lpcp.h"

Go to the source code of this file.

Functions

NTSTATUS NtRequestPort (IN HANDLE PortHandle, IN PPORT_MESSAGE RequestMessage)
NTSTATUS NtRequestWaitReplyPort (IN HANDLE PortHandle, IN PPORT_MESSAGE RequestMessage, OUT PPORT_MESSAGE ReplyMessage)
NTSTATUS LpcRequestPort (IN PVOID PortAddress, IN PPORT_MESSAGE RequestMessage)
NTSTATUS LpcRequestWaitReplyPort (IN PVOID PortAddress, IN PPORT_MESSAGE RequestMessage, OUT PPORT_MESSAGE ReplyMessage)


Function Documentation

NTSTATUS LpcRequestPort IN PVOID  PortAddress,
IN PPORT_MESSAGE  RequestMessage
 

Definition at line 1181 of file lpcsend.c.

References CLIENT_COMMUNICATION_PORT, _LPCP_PORT_OBJECT::ConnectedPort, _LPCP_PORT_OBJECT::ConnectionPort, _LPCP_MESSAGE::Entry, FALSE, _LPCP_PORT_OBJECT::Flags, KeEnterCriticalRegion, KeLeaveCriticalRegion, KeReleaseSemaphore(), KernelMode, KeSetEvent(), KPROCESSOR_MODE, L, LPC_RELEASE_WAIT_INCREMENT, LpcpAcquireLpcpLock, LpcpAllocateFromPortZone(), LpcpFreeToPortZone(), LpcpGenerateMessageId, LpcpGetCreatorName(), LpcpMoveMessage(), LpcpReleaseLpcpLock, LpcpTrace, _LPCP_PORT_OBJECT::MaxMessageLength, _LPCP_PORT_OBJECT::MsgQueue, NULL, PAGED_CODE, PORT_TYPE, PORT_WAITABLE, _LPCP_PORT_OBJECT::PortContext, _LPCP_MESSAGE::PortContext, PsGetCurrentProcess, PsGetCurrentThread, _LPCP_PORT_QUEUE::ReceiveHead, _LPCP_MESSAGE::RepliedToThread, _LPCP_MESSAGE::Request, RequestMessage, _LPCP_PORT_QUEUE::Semaphore, SERVER_COMMUNICATION_PORT, SERVER_CONNECTION_PORT, TRUE, and _LPCP_PORT_OBJECT::WaitEvent.

Referenced by LpcpDeletePort(), PspExitThread(), and xxxActivateDebugger().

01188 : 01189 01190 This procedure is similar to NtRequestPort but without the Handle based 01191 interface. 01192 01193 Arguments: 01194 01195 PortAddress - Supplies a pointer to the communication port to send 01196 the request message to. 01197 01198 RequestMessage - Specifies a pointer to the request message. The Type 01199 field of the message is set to LPC_DATAGRAM by the service. 01200 01201 Return Value: 01202 01203 NTSTATUS - A status code that indicates whether or not the operation was 01204 successful. 01205 01206 --*/ 01207 01208 { 01209 PLPCP_PORT_OBJECT PortObject = (PLPCP_PORT_OBJECT)PortAddress; 01210 PLPCP_PORT_OBJECT QueuePort; 01211 ULONG MsgType; 01212 PLPCP_MESSAGE Msg; 01213 KPROCESSOR_MODE PreviousMode; 01214 01215 PAGED_CODE(); 01216 01217 // 01218 // Get previous processor mode and validate parameters 01219 // 01220 01221 PreviousMode = KeGetPreviousMode(); 01222 01223 if (RequestMessage->u2.s2.Type != 0) { 01224 01225 MsgType = RequestMessage->u2.s2.Type & ~LPC_KERNELMODE_MESSAGE; 01226 01227 if ((MsgType < LPC_DATAGRAM) || 01228 (MsgType > LPC_CLIENT_DIED)) { 01229 01230 return STATUS_INVALID_PARAMETER; 01231 } 01232 01233 // 01234 // If previous mode is kernel, allow the LPC_KERNELMODE_MESSAGE 01235 // bit to be passed in message type field. 01236 // 01237 01238 if ((PreviousMode == KernelMode) && 01239 (RequestMessage->u2.s2.Type & LPC_KERNELMODE_MESSAGE)) { 01240 01241 MsgType |= LPC_KERNELMODE_MESSAGE; 01242 } 01243 01244 } else { 01245 01246 MsgType = LPC_DATAGRAM; 01247 } 01248 01249 if (RequestMessage->u2.s2.DataInfoOffset != 0) { 01250 01251 return STATUS_INVALID_PARAMETER; 01252 } 01253 01254 // 01255 // Validate the message length 01256 // 01257 01258 if (((ULONG)RequestMessage->u1.s1.TotalLength > PortObject->MaxMessageLength) || 01259 ((ULONG)RequestMessage->u1.s1.TotalLength <= (ULONG)RequestMessage->u1.s1.DataLength)) { 01260 01261 return STATUS_PORT_MESSAGE_TOO_LONG; 01262 } 01263 01264 // 01265 // Allocate a message block 01266 // 01267 01268 LpcpAcquireLpcpLock(); 01269 01270 Msg = (PLPCP_MESSAGE)LpcpAllocateFromPortZone( RequestMessage->u1.s1.TotalLength ); 01271 01272 LpcpReleaseLpcpLock(); 01273 01274 if (Msg == NULL) { 01275 01276 return STATUS_NO_MEMORY; 01277 } 01278 01279 // 01280 // Fill in the message block. 01281 // 01282 01283 Msg->RepliedToThread = NULL; 01284 Msg->PortContext = NULL; 01285 01286 LpcpMoveMessage( &Msg->Request, 01287 RequestMessage, 01288 (RequestMessage + 1), 01289 MsgType, 01290 &PsGetCurrentThread()->Cid ); 01291 01292 // 01293 // Acquire the global Lpc mutex that guards the LpcReplyMessage 01294 // field of the thread and the request message queue. Stamp the 01295 // request message with a serial number, insert the message at 01296 // the tail of the request message queue 01297 // 01298 // This all needs to be performed with APCs disabled to avoid 01299 // the situation where something gets put on the queue and this 01300 // thread gets suspended before being able to release the semaphore. 01301 // 01302 01303 KeEnterCriticalRegion(); 01304 01305 LpcpAcquireLpcpLock(); 01306 01307 if ((PortObject->Flags & PORT_TYPE) != SERVER_CONNECTION_PORT) { 01308 01309 QueuePort = PortObject->ConnectedPort; 01310 01311 if (QueuePort != NULL) { 01312 01313 if ((PortObject->Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) { 01314 01315 Msg->PortContext = QueuePort->PortContext; 01316 QueuePort = PortObject->ConnectionPort; 01317 01318 // 01319 // **** this test and assignment are bogus because we earlier 01320 // unconditionally set the QueuePort value 01321 // 01322 01323 } else if ((PortObject->Flags & PORT_TYPE) != SERVER_COMMUNICATION_PORT) { 01324 01325 QueuePort = PortObject->ConnectionPort; 01326 } 01327 } 01328 01329 } else { 01330 01331 QueuePort = PortObject; 01332 } 01333 01334 // 01335 // At this point we have an LPC message ready to send and if queue port is 01336 // not null then we have a port to actually send the message off to 01337 // 01338 01339 if (QueuePort != NULL) { 01340 01341 Msg->Request.MessageId = LpcpGenerateMessageId(); 01342 Msg->Request.CallbackId = 0; 01343 01344 PsGetCurrentThread()->LpcReplyMessageId = 0; 01345 01346 InsertTailList( &QueuePort->MsgQueue.ReceiveHead, &Msg->Entry ); 01347 01348 LpcpTrace(( "%s Send DataGram (%s) Msg %lx [%08x %08x %08x %08x] to Port %lx (%s)\n", 01349 PsGetCurrentProcess()->ImageFileName, 01350 LpcpMessageTypeName[ Msg->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE ], 01351 Msg, 01352 *((PULONG)(Msg+1)+0), 01353 *((PULONG)(Msg+1)+1), 01354 *((PULONG)(Msg+1)+2), 01355 *((PULONG)(Msg+1)+3), 01356 QueuePort, 01357 LpcpGetCreatorName( QueuePort ))); 01358 01359 // 01360 // Release the mutex, increment the request message queue 01361 // semaphore by one for the newly inserted request message, 01362 // then exit the critical region. 01363 // 01364 01365 LpcpReleaseLpcpLock(); 01366 01367 KeReleaseSemaphore( QueuePort->MsgQueue.Semaphore, 01368 LPC_RELEASE_WAIT_INCREMENT, 01369 1L, 01370 FALSE ); 01371 01372 01373 if ( QueuePort->Flags & PORT_WAITABLE ) { 01374 01375 KeSetEvent( &QueuePort->WaitEvent, 01376 LPC_RELEASE_WAIT_INCREMENT, 01377 FALSE ); 01378 } 01379 01380 KeLeaveCriticalRegion(); 01381 01382 return STATUS_SUCCESS; 01383 01384 } 01385 01386 // 01387 // At this point we have a message but not a valid port to queue it off 01388 // to so we'll release the unused message, release our lock and enable 01389 // APC again 01390 // 01391 01392 LpcpFreeToPortZone( Msg, TRUE ); 01393 01394 LpcpReleaseLpcpLock(); 01395 01396 KeLeaveCriticalRegion(); 01397 01398 // 01399 // And return the error status to our caller 01400 // 01401 01402 return STATUS_PORT_DISCONNECTED; 01403 }

NTSTATUS LpcRequestWaitReplyPort IN PVOID  PortAddress,
IN PPORT_MESSAGE  RequestMessage,
OUT PPORT_MESSAGE  ReplyMessage
 

Definition at line 1407 of file lpcsend.c.

References _ETHREAD::Cid, CLIENT_COMMUNICATION_PORT, _LPCP_PORT_OBJECT::ConnectedPort, _LPCP_PORT_OBJECT::ConnectionPort, _LPCP_MESSAGE::Entry, FALSE, _LPCP_PORT_OBJECT::Flags, KeReadStateSemaphore(), KeReleaseSemaphore(), KernelMode, KeSetEvent(), KeWaitForSingleObject(), KPROCESSOR_MODE, LPC_RELEASE_WAIT_INCREMENT, _ETHREAD::LpcExitThreadCalled, LpcpAcquireLpcpLock, LpcpAllocateFromPortZone(), LpcpFreeToPortZone(), LpcpGenerateCallbackId, LpcpGenerateMessageId, LpcpGetCreatorName(), LpcpMoveMessage(), LpcpReleaseLpcpLock, LpcpTrace, _ETHREAD::LpcReplyChain, _LPCP_PORT_OBJECT::LpcReplyChainHead, _ETHREAD::LpcReplyMessage, _ETHREAD::LpcReplyMessageId, _ETHREAD::LpcReplySemaphore, _LPCP_PORT_OBJECT::MaxMessageLength, _LPCP_PORT_OBJECT::MsgQueue, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObject, PAGED_CODE, PORT_TYPE, PORT_WAITABLE, _LPCP_PORT_OBJECT::PortContext, _LPCP_MESSAGE::PortContext, PsGetCurrentProcess, PsGetCurrentThread, PsLookupProcessThreadByCid(), _LPCP_PORT_QUEUE::ReceiveHead, _LPCP_MESSAGE::RepliedToThread, ReplyMessage(), _LPCP_MESSAGE::Request, RequestMessage, _LPCP_PORT_QUEUE::Semaphore, SERVER_COMMUNICATION_PORT, SERVER_CONNECTION_PORT, Status, THREAD_TO_PROCESS, TRUE, _LPCP_PORT_OBJECT::WaitEvent, WrExecutive, and WrLpcReply.

Referenced by DbgkpSendApiMessage(), ExpRaiseHardError(), and IopSendMessageToTrackService().

01415 : 01416 01417 This procedure is similar to NtRequestWaitReplyPort but without the 01418 handle based interface 01419 01420 Arguments: 01421 01422 PortAddress - Supplies the communication port object to send the 01423 request message to. 01424 01425 RequestMessage - Specifies a pointer to a request message to send. 01426 01427 ReplyMessage - Specifies the address of a variable that will receive the 01428 reply message. This parameter may point to the same buffer as the 01429 RequestMessage parameter. 01430 01431 Return Value: 01432 01433 NTSTATUS - A status code that indicates whether or not the operation was 01434 successful. 01435 01436 --*/ 01437 01438 { 01439 PLPCP_PORT_OBJECT PortObject = (PLPCP_PORT_OBJECT)PortAddress; 01440 PLPCP_PORT_OBJECT QueuePort; 01441 PLPCP_PORT_OBJECT RundownPort; 01442 PKSEMAPHORE ReleaseSemaphore; 01443 NTSTATUS Status; 01444 ULONG MsgType; 01445 PLPCP_MESSAGE Msg; 01446 PETHREAD CurrentThread; 01447 PETHREAD WakeupThread; 01448 BOOLEAN CallbackRequest; 01449 KPROCESSOR_MODE PreviousMode; 01450 01451 PAGED_CODE(); 01452 01453 CurrentThread = PsGetCurrentThread(); 01454 01455 if (CurrentThread->LpcExitThreadCalled) { 01456 01457 return STATUS_THREAD_IS_TERMINATING; 01458 } 01459 01460 // 01461 // Get previous processor mode and validate parameters 01462 // 01463 01464 PreviousMode = KeGetPreviousMode(); 01465 MsgType = RequestMessage->u2.s2.Type & ~LPC_KERNELMODE_MESSAGE; 01466 CallbackRequest = FALSE; 01467 01468 switch (MsgType) { 01469 01470 case 0: 01471 01472 MsgType = LPC_REQUEST; 01473 break; 01474 01475 case LPC_REQUEST: 01476 01477 CallbackRequest = TRUE; 01478 break; 01479 01480 case LPC_CLIENT_DIED: 01481 case LPC_PORT_CLOSED: 01482 case LPC_EXCEPTION: 01483 case LPC_DEBUG_EVENT: 01484 case LPC_ERROR_EVENT: 01485 01486 break; 01487 01488 default : 01489 01490 return STATUS_INVALID_PARAMETER; 01491 } 01492 01493 // 01494 // Allow the LPC_KERNELMODE_MESSAGE 01495 // bit to be passed in message type field. Don't check the previous mode !!! 01496 // 01497 01498 if ( RequestMessage->u2.s2.Type & LPC_KERNELMODE_MESSAGE) { 01499 01500 MsgType |= LPC_KERNELMODE_MESSAGE; 01501 } 01502 01503 RequestMessage->u2.s2.Type = (CSHORT)MsgType; 01504 01505 // 01506 // Validate the message length 01507 // 01508 01509 if (((ULONG)RequestMessage->u1.s1.TotalLength > PortObject->MaxMessageLength) || 01510 ((ULONG)RequestMessage->u1.s1.TotalLength <= (ULONG)RequestMessage->u1.s1.DataLength)) { 01511 01512 return STATUS_PORT_MESSAGE_TOO_LONG; 01513 } 01514 01515 // 01516 // Determine which port to queue the message to and get client 01517 // port context if client sending to server. Also validate 01518 // length of message being sent. 01519 // 01520 01521 LpcpAcquireLpcpLock(); 01522 01523 Msg = (PLPCP_MESSAGE)LpcpAllocateFromPortZone( RequestMessage->u1.s1.TotalLength ); 01524 01525 LpcpReleaseLpcpLock(); 01526 01527 if (Msg == NULL) { 01528 01529 return STATUS_NO_MEMORY; 01530 } 01531 01532 if (CallbackRequest) { 01533 01534 // 01535 // Check for a valid request message id 01536 // 01537 01538 if (RequestMessage->MessageId == 0) { 01539 01540 LpcpFreeToPortZone( Msg, FALSE ); 01541 01542 return STATUS_INVALID_PARAMETER; 01543 } 01544 01545 // 01546 // Translate the ClientId from the request into a 01547 // thread pointer. This is a referenced pointer to keep the thread 01548 // from evaporating out from under us. 01549 // 01550 01551 Status = PsLookupProcessThreadByCid( &RequestMessage->ClientId, 01552 NULL, 01553 &WakeupThread ); 01554 01555 if (!NT_SUCCESS( Status )) { 01556 01557 LpcpFreeToPortZone( Msg, FALSE ); 01558 01559 return Status; 01560 } 01561 01562 // 01563 // Acquire the mutex that gaurds the LpcReplyMessage field of 01564 // the thread and get the pointer to the message that the thread 01565 // is waiting for a reply to. 01566 // 01567 01568 LpcpAcquireLpcpLock(); 01569 01570 // 01571 // See if the thread is waiting for a reply to the message 01572 // specified on this call. If not then a bogus message 01573 // has been specified, so release the mutex, dereference the thread 01574 // and return failure. 01575 // 01576 01577 if ((WakeupThread->LpcReplyMessageId != RequestMessage->MessageId) 01578 01579 || 01580 01581 ((WakeupThread->LpcReplyMessage != NULL) && 01582 (((PLPCP_MESSAGE)(WakeupThread->LpcReplyMessage))->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) != LPC_REQUEST)) { 01583 01584 LpcpFreeToPortZone( Msg, TRUE ); 01585 01586 LpcpReleaseLpcpLock(); 01587 01588 ObDereferenceObject( WakeupThread ); 01589 01590 return STATUS_REPLY_MESSAGE_MISMATCH; 01591 } 01592 01593 QueuePort = NULL; 01594 Msg->PortContext = NULL; 01595 01596 if ((PortObject->Flags & PORT_TYPE) == SERVER_CONNECTION_PORT) { 01597 01598 RundownPort = PortObject; 01599 01600 } else { 01601 01602 RundownPort = PortObject->ConnectedPort; 01603 01604 if (RundownPort == NULL) { 01605 01606 LpcpFreeToPortZone( Msg, TRUE ); 01607 01608 LpcpReleaseLpcpLock(); 01609 01610 ObDereferenceObject( WakeupThread ); 01611 01612 return STATUS_PORT_DISCONNECTED; 01613 } 01614 01615 if ((PortObject->Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) { 01616 01617 Msg->PortContext = RundownPort->PortContext; 01618 } 01619 } 01620 01621 // 01622 // Allocate and initialize a request message 01623 // 01624 01625 LpcpMoveMessage( &Msg->Request, 01626 RequestMessage, 01627 (RequestMessage + 1), 01628 0, 01629 &CurrentThread->Cid ); 01630 01631 Msg->Request.CallbackId = LpcpGenerateCallbackId(); 01632 01633 LpcpTrace(( "%s CallBack Request (%s) Msg %lx (%u.%u) [%08x %08x %08x %08x] to Thread %lx (%s)\n", 01634 PsGetCurrentProcess()->ImageFileName, 01635 LpcpMessageTypeName[ Msg->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE ], 01636 Msg, 01637 Msg->Request.MessageId, 01638 Msg->Request.CallbackId, 01639 *((PULONG)(Msg+1)+0), 01640 *((PULONG)(Msg+1)+1), 01641 *((PULONG)(Msg+1)+2), 01642 *((PULONG)(Msg+1)+3), 01643 WakeupThread, 01644 THREAD_TO_PROCESS( WakeupThread )->ImageFileName )); 01645 01646 // 01647 // Add an extra reference so LpcExitThread does not evaporate 01648 // the pointer before we get to the wait below 01649 // 01650 01651 ObReferenceObject( WakeupThread ); 01652 01653 Msg->RepliedToThread = WakeupThread; 01654 01655 WakeupThread->LpcReplyMessageId = 0; 01656 WakeupThread->LpcReplyMessage = (PVOID)Msg; 01657 01658 // 01659 // Remove the thread from the reply rundown list as we are sending a callback 01660 // 01661 01662 if (!IsListEmpty( &WakeupThread->LpcReplyChain )) { 01663 01664 RemoveEntryList( &WakeupThread->LpcReplyChain ); 01665 01666 InitializeListHead( &WakeupThread->LpcReplyChain ); 01667 } 01668 01669 CurrentThread->LpcReplyMessageId = Msg->Request.MessageId; 01670 CurrentThread->LpcReplyMessage = NULL; 01671 01672 InsertTailList( &RundownPort->LpcReplyChainHead, &CurrentThread->LpcReplyChain ); 01673 01674 LpcpReleaseLpcpLock(); 01675 01676 // 01677 // Wake up the thread that is waiting for an answer to its request 01678 // inside of NtRequestWaitReplyPort or NtReplyWaitReplyPort 01679 // 01680 01681 ReleaseSemaphore = &WakeupThread->LpcReplySemaphore; 01682 01683 } else { 01684 01685 // 01686 // There is no callbreak requested 01687 // 01688 01689 LpcpMoveMessage( &Msg->Request, 01690 RequestMessage, 01691 (RequestMessage + 1), 01692 0, 01693 &CurrentThread->Cid ); 01694 01695 // 01696 // Acquire the global Lpc mutex that gaurds the LpcReplyMessage 01697 // field of the thread and the request message queue. Stamp the 01698 // request message with a serial number, insert the message at 01699 // the tail of the request message queue and remember the address 01700 // of the message in the LpcReplyMessage field for the current thread. 01701 // 01702 01703 LpcpAcquireLpcpLock(); 01704 01705 Msg->PortContext = NULL; 01706 01707 if ((PortObject->Flags & PORT_TYPE) != SERVER_CONNECTION_PORT) { 01708 01709 QueuePort = PortObject->ConnectedPort; 01710 01711 if (QueuePort == NULL) { 01712 01713 LpcpFreeToPortZone( Msg, TRUE ); 01714 01715 LpcpReleaseLpcpLock(); 01716 01717 return STATUS_PORT_DISCONNECTED; 01718 } 01719 01720 RundownPort = QueuePort; 01721 01722 if ((PortObject->Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) { 01723 01724 Msg->PortContext = QueuePort->PortContext; 01725 QueuePort = PortObject->ConnectionPort; 01726 01727 } else if ((PortObject->Flags & PORT_TYPE) != SERVER_COMMUNICATION_PORT) { 01728 01729 QueuePort = PortObject->ConnectionPort; 01730 } 01731 01732 } else { 01733 01734 QueuePort = PortObject; 01735 RundownPort = PortObject; 01736 } 01737 01738 Msg->RepliedToThread = NULL; 01739 Msg->Request.MessageId = LpcpGenerateMessageId(); 01740 Msg->Request.CallbackId = 0; 01741 01742 CurrentThread->LpcReplyMessageId = Msg->Request.MessageId; 01743 CurrentThread->LpcReplyMessage = NULL; 01744 01745 InsertTailList( &QueuePort->MsgQueue.ReceiveHead, &Msg->Entry ); 01746 InsertTailList( &RundownPort->LpcReplyChainHead, &CurrentThread->LpcReplyChain ); 01747 01748 LpcpTrace(( "%s Send Request (%s) Msg %lx (%u) [%08x %08x %08x %08x] to Port %lx (%s)\n", 01749 PsGetCurrentProcess()->ImageFileName, 01750 LpcpMessageTypeName[ Msg->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE ], 01751 Msg, 01752 Msg->Request.MessageId, 01753 *((PULONG)(Msg+1)+0), 01754 *((PULONG)(Msg+1)+1), 01755 *((PULONG)(Msg+1)+2), 01756 *((PULONG)(Msg+1)+3), 01757 QueuePort, 01758 LpcpGetCreatorName( QueuePort ))); 01759 01760 LpcpReleaseLpcpLock(); 01761 01762 // 01763 // Increment the request message queue semaphore by one for 01764 // the newly inserted request message. Release the spin 01765 // lock, while remaining at the dispatcher IRQL. Then wait for the 01766 // reply to this request by waiting on the LpcReplySemaphore 01767 // for the current thread. 01768 // 01769 01770 ReleaseSemaphore = QueuePort->MsgQueue.Semaphore; 01771 01772 if ( QueuePort->Flags & PORT_WAITABLE ) { 01773 01774 KeSetEvent( &QueuePort->WaitEvent, 01775 LPC_RELEASE_WAIT_INCREMENT, 01776 FALSE ); 01777 } 01778 } 01779 01780 // 01781 // At this point we've enqueued our request and if necessary 01782 // set ourselves up for the callback or reply. 01783 // 01784 // So now wake up the other end 01785 // 01786 01787 Status = KeReleaseSemaphore( ReleaseSemaphore, 01788 1, 01789 1, 01790 FALSE ); 01791 01792 if (CallbackRequest) { 01793 01794 ObDereferenceObject( WakeupThread ); 01795 } 01796 01797 // 01798 // And wait for a reply 01799 // 01800 01801 Status = KeWaitForSingleObject( &CurrentThread->LpcReplySemaphore, 01802 WrLpcReply, 01803 KernelMode, 01804 FALSE, 01805 NULL ); 01806 01807 if (Status == STATUS_USER_APC) { 01808 01809 // 01810 // if the semaphore is signaled, then clear it 01811 // 01812 01813 if (KeReadStateSemaphore( &CurrentThread->LpcReplySemaphore )) { 01814 01815 KeWaitForSingleObject( &CurrentThread->LpcReplySemaphore, 01816 WrExecutive, 01817 KernelMode, 01818 FALSE, 01819 NULL ); 01820 01821 Status = STATUS_SUCCESS; 01822 } 01823 } 01824 01825 // 01826 // Acquire the LPC mutex. Remove the reply message from the current thread 01827 // 01828 01829 LpcpAcquireLpcpLock(); 01830 01831 Msg = CurrentThread->LpcReplyMessage; 01832 01833 CurrentThread->LpcReplyMessage = NULL; 01834 CurrentThread->LpcReplyMessageId = 0; 01835 01836 // 01837 // Remove the thread from the reply rundown list in case we did not wakeup due to 01838 // a reply 01839 // 01840 01841 if (!IsListEmpty( &CurrentThread->LpcReplyChain )) { 01842 01843 RemoveEntryList( &CurrentThread->LpcReplyChain ); 01844 01845 InitializeListHead( &CurrentThread->LpcReplyChain ); 01846 } 01847 01848 #if DBG 01849 if (Msg != NULL) { 01850 01851 LpcpTrace(( "%s Got Reply Msg %lx (%u) [%08x %08x %08x %08x] for Thread %lx (%s)\n", 01852 PsGetCurrentProcess()->ImageFileName, 01853 Msg, 01854 Msg->Request.MessageId, 01855 *((PULONG)(Msg+1)+0), 01856 *((PULONG)(Msg+1)+1), 01857 *((PULONG)(Msg+1)+2), 01858 *((PULONG)(Msg+1)+3), 01859 CurrentThread, 01860 THREAD_TO_PROCESS( CurrentThread )->ImageFileName )); 01861 } 01862 #endif 01863 01864 LpcpReleaseLpcpLock(); 01865 01866 // 01867 // If the wait succeeded, copy the reply to the reply buffer. 01868 // 01869 01870 if (Status == STATUS_SUCCESS) { 01871 01872 if (Msg != NULL) { 01873 01874 LpcpMoveMessage( ReplyMessage, 01875 &Msg->Request, 01876 (&Msg->Request) + 1, 01877 0, 01878 NULL ); 01879 01880 // 01881 // Acquire the LPC mutex and decrement the reference count for the 01882 // message. If the reference count goes to zero the message will be 01883 // deleted. 01884 // 01885 01886 LpcpAcquireLpcpLock(); 01887 01888 if (Msg->RepliedToThread != NULL) { 01889 01890 ObDereferenceObject( Msg->RepliedToThread ); 01891 01892 Msg->RepliedToThread = NULL; 01893 } 01894 01895 LpcpFreeToPortZone( Msg, TRUE ); 01896 01897 LpcpReleaseLpcpLock(); 01898 01899 } else { 01900 01901 Status = STATUS_LPC_REPLY_LOST; 01902 } 01903 01904 } else { 01905 01906 // 01907 // Wait failed, acquire the LPC mutex and free the message. 01908 // 01909 01910 LpcpAcquireLpcpLock(); 01911 01912 if (Msg != NULL) { 01913 01914 LpcpFreeToPortZone( Msg, TRUE ); 01915 } 01916 01917 LpcpReleaseLpcpLock(); 01918 } 01919 01920 // 01921 // And return to our caller 01922 // 01923 01924 return Status; 01925 }

NTSTATUS NtRequestPort IN HANDLE  PortHandle,
IN PPORT_MESSAGE  RequestMessage
 

Definition at line 32 of file lpcsend.c.

References CLIENT_COMMUNICATION_PORT, _LPCP_PORT_OBJECT::ConnectedPort, _LPCP_PORT_OBJECT::ConnectionPort, _LPCP_MESSAGE::Entry, EXCEPTION_EXECUTE_HANDLER, FALSE, _LPCP_PORT_OBJECT::Flags, KeEnterCriticalRegion, KeLeaveCriticalRegion, KeReleaseSemaphore(), KernelMode, KeSetEvent(), KPROCESSOR_MODE, L, LPC_RELEASE_WAIT_INCREMENT, LpcpAcquireLpcpLock, LpcpAllocateFromPortZone(), LpcpFreeToPortZone(), LpcpGenerateMessageId, LpcpGetCreatorName(), LpcpMoveMessage(), LpcpReferencePortObject, LpcpReleaseLpcpLock, LpcpTrace, _LPCP_PORT_OBJECT::MaxMessageLength, _LPCP_PORT_OBJECT::MsgQueue, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObject, PAGED_CODE, PORT_DELETED, PORT_TYPE, PORT_WAITABLE, _LPCP_PORT_OBJECT::PortContext, _LPCP_MESSAGE::PortContext, PortHandle, ProbeForRead, PsGetCurrentProcess, PsGetCurrentThread, _LPCP_PORT_QUEUE::ReceiveHead, _LPCP_MESSAGE::RepliedToThread, _LPCP_MESSAGE::Request, RequestMessage, _LPCP_PORT_QUEUE::Semaphore, SERVER_COMMUNICATION_PORT, SERVER_CONNECTION_PORT, Status, TRUE, and _LPCP_PORT_OBJECT::WaitEvent.

Referenced by DbgSspCreateProcess(), DbgSspCreateThread(), DbgSspException(), DbgSspExitProcess(), DbgSspExitThread(), DbgSspLoadDll(), DbgSspUnloadDll(), and IopErrorLogThread().

00039 : 00040 00041 A client and server process send datagram messages using this procedure. 00042 00043 The message pointed to by the RequestMessage parameter is placed in the 00044 message queue of the port connected to the communication port specified 00045 by the PortHandle parameter. This service returns an error if PortHandle 00046 is invalid or if the MessageId field of the PortMessage structure is 00047 non-zero. 00048 00049 Arguments: 00050 00051 PortHandle - Specifies the handle of the communication port to send 00052 the request message to. 00053 00054 RequestMessage - Specifies a pointer to the request message. The Type 00055 field of the message is set to LPC_DATAGRAM by the service. 00056 00057 Return Value: 00058 00059 NTSTATUS - A status code that indicates whether or not the operation was 00060 successful. 00061 00062 --*/ 00063 00064 { 00065 PLPCP_PORT_OBJECT PortObject; 00066 PLPCP_PORT_OBJECT QueuePort; 00067 PORT_MESSAGE CapturedRequestMessage; 00068 ULONG MsgType; 00069 KPROCESSOR_MODE PreviousMode; 00070 NTSTATUS Status; 00071 PLPCP_MESSAGE Msg; 00072 00073 PAGED_CODE(); 00074 00075 // 00076 // Get previous processor mode and validate parameters 00077 // 00078 00079 PreviousMode = KeGetPreviousMode(); 00080 00081 if (PreviousMode != KernelMode) { 00082 00083 try { 00084 00085 ProbeForRead( RequestMessage, 00086 sizeof( *RequestMessage ), 00087 sizeof( ULONG )); 00088 00089 CapturedRequestMessage = *RequestMessage; 00090 CapturedRequestMessage.u2.s2.Type &= ~LPC_KERNELMODE_MESSAGE; 00091 00092 } except( EXCEPTION_EXECUTE_HANDLER ) { 00093 00094 return GetExceptionCode(); 00095 } 00096 00097 if (CapturedRequestMessage.u2.s2.Type != 0) { 00098 00099 return STATUS_INVALID_PARAMETER; 00100 } 00101 00102 } else { 00103 00104 // 00105 // This is a kernel mode caller 00106 // 00107 00108 CapturedRequestMessage = *RequestMessage; 00109 00110 if ((CapturedRequestMessage.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) != 0) { 00111 00112 return STATUS_INVALID_PARAMETER; 00113 } 00114 } 00115 00116 // 00117 // Make sure that the caller has given us some data to send 00118 // 00119 00120 if (CapturedRequestMessage.u2.s2.DataInfoOffset != 0) { 00121 00122 return STATUS_INVALID_PARAMETER; 00123 } 00124 00125 // 00126 // Make sure DataLength is valid with respect to header size and total length 00127 // 00128 00129 if ((((CLONG)CapturedRequestMessage.u1.s1.DataLength) + sizeof( PORT_MESSAGE )) > 00130 ((CLONG)CapturedRequestMessage.u1.s1.TotalLength)) { 00131 00132 return STATUS_INVALID_PARAMETER; 00133 } 00134 00135 // 00136 // Reference the communication port object by handle. Return status if 00137 // unsuccessful. 00138 // 00139 00140 Status = LpcpReferencePortObject( PortHandle, 00141 0, 00142 PreviousMode, 00143 &PortObject ); 00144 00145 if (!NT_SUCCESS( Status )) { 00146 00147 return Status; 00148 } 00149 00150 // 00151 // Validate the message length 00152 // 00153 00154 if (((ULONG)CapturedRequestMessage.u1.s1.TotalLength > PortObject->MaxMessageLength) || 00155 ((ULONG)CapturedRequestMessage.u1.s1.TotalLength <= (ULONG)CapturedRequestMessage.u1.s1.DataLength)) { 00156 00157 ObDereferenceObject( PortObject ); 00158 00159 return STATUS_PORT_MESSAGE_TOO_LONG; 00160 } 00161 00162 // 00163 // Determine which port to queue the message to and get client 00164 // port context if client sending to server. Also validate 00165 // length of message being sent. 00166 // 00167 00168 // 00169 // Allocate and initialize the LPC message to send off 00170 // 00171 00172 LpcpAcquireLpcpLock(); 00173 00174 Msg = (PLPCP_MESSAGE)LpcpAllocateFromPortZone( CapturedRequestMessage.u1.s1.TotalLength ); 00175 00176 LpcpReleaseLpcpLock(); 00177 00178 if (Msg == NULL) { 00179 00180 ObDereferenceObject( PortObject ); 00181 00182 return STATUS_NO_MEMORY; 00183 } 00184 00185 Msg->RepliedToThread = NULL; 00186 Msg->PortContext = NULL; 00187 MsgType = CapturedRequestMessage.u2.s2.Type | LPC_DATAGRAM; 00188 00189 try { 00190 00191 LpcpMoveMessage( &Msg->Request, 00192 &CapturedRequestMessage, 00193 (RequestMessage + 1), 00194 MsgType, 00195 &PsGetCurrentThread()->Cid ); 00196 00197 } except( EXCEPTION_EXECUTE_HANDLER ) { 00198 00199 Status = GetExceptionCode(); 00200 } 00201 00202 if (!NT_SUCCESS( Status )) { 00203 00204 LpcpFreeToPortZone( Msg, FALSE ); 00205 00206 ObDereferenceObject( PortObject ); 00207 00208 return Status; 00209 } 00210 00211 // 00212 // Acquire the global Lpc mutex that guards the LpcReplyMessage 00213 // field of the thread and the request message queue. Stamp the 00214 // request message with a serial number, insert the message at 00215 // the tail of the request message queue and remember the address 00216 // of the message in the LpcReplyMessage field for the current thread. 00217 // 00218 // This all needs to be performed with APCs disabled to avoid 00219 // the situation where something gets put on the queue and this 00220 // thread gets suspended before being able to release the semaphore. 00221 // 00222 00223 KeEnterCriticalRegion(); 00224 00225 LpcpAcquireLpcpLock(); 00226 00227 // 00228 // Based on what type of port the caller gave us we'll need to get 00229 // the port to actually queue the message off to. 00230 // 00231 00232 if ((PortObject->Flags & PORT_TYPE) != SERVER_CONNECTION_PORT) { 00233 00234 // 00235 // The caller didn't give us a connection port so find the 00236 // connection port for this port. If it is null then we'll 00237 // fall through without sending a message 00238 // 00239 00240 QueuePort = PortObject->ConnectedPort; 00241 00242 // 00243 // Check if the queue port is in process of going away 00244 // 00245 00246 if ( (QueuePort != NULL) && 00247 (QueuePort->Flags & PORT_DELETED) ){ 00248 00249 // DbgPrint("Queueport %08lx is going away\n", QueuePort); 00250 00251 QueuePort = NULL; 00252 } 00253 00254 if ( QueuePort != NULL) { 00255 00256 // 00257 // If the port is a client communication port then give the 00258 // message the proper port context 00259 // 00260 00261 if ((PortObject->Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) { 00262 00263 Msg->PortContext = QueuePort->PortContext; 00264 QueuePort = PortObject->ConnectionPort; 00265 00266 // 00267 // **** this test and conditional assignment looks bogus because 00268 // we already set queue port 00269 // 00270 00271 } else if ((PortObject->Flags & PORT_TYPE) != SERVER_COMMUNICATION_PORT) { 00272 00273 QueuePort = PortObject->ConnectionPort; 00274 } 00275 } 00276 00277 } else { 00278 00279 // 00280 // The caller supplied a server connection port so that is the port 00281 // we queue off to 00282 // 00283 00284 QueuePort = PortObject; 00285 } 00286 00287 // 00288 // At this point we have an LPC message ready to send and if queue port is 00289 // not null then we have a port to actually send the message off to 00290 // 00291 00292 if (QueuePort != NULL) { 00293 00294 // 00295 // Reference the QueuePort to prevent this port evaporating under us 00296 // 00297 00298 ObReferenceObject( QueuePort ); 00299 00300 // 00301 // Finish filling in the messsage and then insert it in the queue 00302 // 00303 00304 Msg->Request.MessageId = LpcpGenerateMessageId(); 00305 Msg->Request.CallbackId = 0; 00306 00307 PsGetCurrentThread()->LpcReplyMessageId = 0; 00308 00309 InsertTailList( &QueuePort->MsgQueue.ReceiveHead, &Msg->Entry ); 00310 00311 LpcpTrace(( "%s Send DataGram (%s) Msg %lx [%08x %08x %08x %08x] to Port %lx (%s)\n", 00312 PsGetCurrentProcess()->ImageFileName, 00313 LpcpMessageTypeName[ Msg->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE ], 00314 Msg, 00315 *((PULONG)(Msg+1)+0), 00316 *((PULONG)(Msg+1)+1), 00317 *((PULONG)(Msg+1)+2), 00318 *((PULONG)(Msg+1)+3), 00319 QueuePort, 00320 LpcpGetCreatorName( QueuePort ))); 00321 00322 // 00323 // Release the mutex, increment the request message queue 00324 // semaphore by one for the newly inserted request message 00325 // then exit the critical region. 00326 // 00327 00328 LpcpReleaseLpcpLock(); 00329 00330 KeReleaseSemaphore( QueuePort->MsgQueue.Semaphore, 00331 LPC_RELEASE_WAIT_INCREMENT, 00332 1L, 00333 FALSE ); 00334 00335 // 00336 // If this is a waitable port then we'll need to set the event for 00337 // anyone that was waiting on the port 00338 // 00339 00340 if ( QueuePort->Flags & PORT_WAITABLE ) { 00341 00342 KeSetEvent( &QueuePort->WaitEvent, 00343 LPC_RELEASE_WAIT_INCREMENT, 00344 FALSE ); 00345 } 00346 00347 // 00348 // Exit the critical region and release the port object 00349 // 00350 00351 KeLeaveCriticalRegion(); 00352 00353 ObDereferenceObject( QueuePort ); 00354 ObDereferenceObject( PortObject ); 00355 00356 // 00357 // And return to our caller. This is the only successful way out 00358 // of this routine 00359 // 00360 00361 return Status; 00362 00363 } 00364 00365 // 00366 // At this point we have a message but not a valid port to queue it off 00367 // to so we'll free up the port object and release the unused message 00368 // 00369 // We have to do the dereference outside of the lpcp lock because the 00370 // object manager now speical cases lpc object types and synchronizes 00371 // their removal with the lpcp lock. 00372 // 00373 00374 LpcpFreeToPortZone( Msg, TRUE ); 00375 00376 // 00377 // Release our lock and enable APC again 00378 // 00379 00380 LpcpReleaseLpcpLock(); 00381 00382 ObDereferenceObject( PortObject ); 00383 00384 KeLeaveCriticalRegion(); 00385 00386 // 00387 // And return the error status to our caller 00388 // 00389 00390 return STATUS_PORT_DISCONNECTED; 00391 }

NTSTATUS NtRequestWaitReplyPort IN HANDLE  PortHandle,
IN PPORT_MESSAGE  RequestMessage,
OUT PPORT_MESSAGE  ReplyMessage
 

Definition at line 395 of file lpcsend.c.

References _ETHREAD::Cid, CLIENT_COMMUNICATION_PORT, _LPCP_PORT_OBJECT::ConnectedPort, _LPCP_PORT_OBJECT::ConnectionPort, _LPCP_MESSAGE::Entry, EXCEPTION_EXECUTE_HANDLER, FALSE, _LPCP_PORT_OBJECT::Flags, KeReadStateSemaphore(), KeReleaseSemaphore(), KernelMode, KeSetEvent(), KeWaitForSingleObject(), KPROCESSOR_MODE, LPC_RELEASE_WAIT_INCREMENT, _ETHREAD::LpcExitThreadCalled, LpcpAcquireLpcpLock, LpcpAllocateFromPortZone(), LpcpFreeToPortZone(), LpcpGenerateCallbackId, LpcpGenerateMessageId, LpcpGetCreatorName(), LpcpMoveMessage(), LpcpPrint, LpcpReferencePortObject, LpcpReleaseLpcpLock, LpcpSaveDataInfoMessage(), LpcpTrace, _ETHREAD::LpcReplyChain, _LPCP_PORT_OBJECT::LpcReplyChainHead, _ETHREAD::LpcReplyMessage, _ETHREAD::LpcReplyMessageId, _ETHREAD::LpcReplySemaphore, _LPCP_PORT_OBJECT::MaxMessageLength, _LPCP_PORT_OBJECT::MsgQueue, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObject, PAGED_CODE, PORT_TYPE, PORT_WAITABLE, _LPCP_PORT_OBJECT::PortContext, _LPCP_MESSAGE::PortContext, PortHandle, ProbeForRead, ProbeForWrite(), PsGetCurrentProcess, PsGetCurrentThread, PsLookupProcessThreadByCid(), _LPCP_PORT_QUEUE::ReceiveHead, _LPCP_MESSAGE::RepliedToThread, ReplyMessage(), _LPCP_MESSAGE::Request, RequestMessage, _LPCP_PORT_QUEUE::Semaphore, SERVER_COMMUNICATION_PORT, SERVER_CONNECTION_PORT, Status, THREAD_TO_PROCESS, TRUE, _LPCP_PORT_OBJECT::WaitEvent, WrExecutive, and WrLpcReply.

Referenced by BrokenConnection(), CsrClientCallServer(), DbgUiContinue(), DbgUiWaitStateChange(), ReplyMessageToTerminalServer(), RtlCallbackLpcClient(), SendRequest(), ShadowHotkey(), and TerminalServerRequestThread().

00403 : 00404 00405 A client and server process can send a request and wait for a reply using 00406 the NtRequestWaitReplyPort service. 00407 00408 If the Type field of the RequestMessage structure is euqal to LPC_REQUEST, 00409 then this is identified as a callback request. The ClientId and MessageId 00410 fields are used to identify the thread that is waiting for a reply. This 00411 thread is unblocked and the current thread that called this service then 00412 blocks waiting for a reply. 00413 00414 The Type field of the message is set to LPC_REQUEST by the service. 00415 Otherwise the Type field of the message must be zero and it will be set to 00416 LPC_REQUEST by the service. The message pointed to by the RequestMessage 00417 parameter is placed in the message queue of the port connected to the 00418 communication port specified by the PortHandle parameter. This service 00419 returns an error if PortHandle is invalid. The calling thread then blocks 00420 waiting for a reply. 00421 00422 The reply message is stored in the location pointed to by the ReplyMessage 00423 parameter. The ClientId, MessageId and message type fields will be filled 00424 in by the service. 00425 00426 Arguments: 00427 00428 PortHandle - Specifies the handle of the communication port to send the 00429 request message to. 00430 00431 RequestMessage - Specifies a pointer to a request message to send. 00432 00433 ReplyMessage - Specifies the address of a variable that will receive the 00434 reply message. This parameter may point to the same buffer as the 00435 RequestMessage parameter. 00436 00437 Return Value: 00438 00439 NTSTATUS - A status code that indicates whether or not the operation was 00440 successful. 00441 00442 --*/ 00443 00444 { 00445 PLPCP_PORT_OBJECT PortObject; 00446 PLPCP_PORT_OBJECT QueuePort; 00447 PLPCP_PORT_OBJECT RundownPort; 00448 PORT_MESSAGE CapturedRequestMessage; 00449 ULONG MsgType; 00450 PKSEMAPHORE ReleaseSemaphore; 00451 KPROCESSOR_MODE PreviousMode; 00452 NTSTATUS Status; 00453 PLPCP_MESSAGE Msg; 00454 PETHREAD CurrentThread; 00455 PETHREAD WakeupThread; 00456 BOOLEAN CallbackRequest; 00457 PORT_DATA_INFORMATION CapturedDataInfo; 00458 00459 PAGED_CODE(); 00460 00461 // 00462 // We cannot wait for a reply if the current thread is exiting 00463 // 00464 00465 CurrentThread = PsGetCurrentThread(); 00466 00467 if (CurrentThread->LpcExitThreadCalled) { 00468 00469 return STATUS_THREAD_IS_TERMINATING; 00470 } 00471 00472 // 00473 // Get previous processor mode and probe output arguments if necessary. 00474 // 00475 00476 PreviousMode = KeGetPreviousMode(); 00477 00478 if (PreviousMode != KernelMode) { 00479 00480 try { 00481 00482 ProbeForRead( RequestMessage, 00483 sizeof( *RequestMessage ), 00484 sizeof( ULONG )); 00485 00486 CapturedRequestMessage = *RequestMessage; 00487 CapturedRequestMessage.u2.s2.Type &= ~LPC_KERNELMODE_MESSAGE; 00488 00489 ProbeForWrite( ReplyMessage, 00490 sizeof( *ReplyMessage ), 00491 sizeof( ULONG )); 00492 00493 // 00494 // Make sure that if this message has a data info offset that 00495 // the port data information actually fits in the message. 00496 // 00497 // We first check that the DataInfoOffset doesn't put us beyond 00498 // the end of the message. 00499 // 00500 // Then we capture the data info record and compute a pointer to 00501 // the first unused data entry based on the supplied count. If 00502 // the start of the message plus its total length doesn't come 00503 // up to the first unsused data entry then the last valid data 00504 // entry doesn't fit in the message buffer. Also if the data 00505 // entry pointer that we compute is less than the data info 00506 // pointer then we must have wrapped. 00507 // 00508 00509 if (CapturedRequestMessage.u2.s2.DataInfoOffset != 0) { 00510 00511 PPORT_DATA_INFORMATION DataInfo; 00512 PPORT_DATA_ENTRY DataEntry; 00513 00514 if (((ULONG)CapturedRequestMessage.u2.s2.DataInfoOffset) > (CapturedRequestMessage.u1.s1.TotalLength - sizeof(PORT_DATA_INFORMATION))) { 00515 00516 return STATUS_INVALID_PARAMETER; 00517 } 00518 00519 if ((ULONG)CapturedRequestMessage.u2.s2.DataInfoOffset < sizeof(PORT_MESSAGE)) { 00520 00521 return STATUS_INVALID_PARAMETER; 00522 } 00523 00524 DataInfo = (PPORT_DATA_INFORMATION)(((PUCHAR)RequestMessage) + CapturedRequestMessage.u2.s2.DataInfoOffset); 00525 00526 ProbeForRead( DataInfo, 00527 sizeof( *DataInfo ), 00528 sizeof( ULONG )); 00529 00530 CapturedDataInfo = *DataInfo; 00531 00532 DataEntry = &(DataInfo->DataEntries[CapturedDataInfo.CountDataEntries]); 00533 00534 00535 // 00536 // The computation of above address, could overflow. So we have to return STATUS_INVALID_PARAMETER if : 00537 // CountDataEntries * sizeof(DataEntries) < CountDataEntries 00538 // 00539 // But CountDataEntries * sizeof(DataEntries) = DataEntry - DataInfo - sizeof(CountDataEntries) 00540 // and the final condition will be: 00541 // 00542 // DataEntry - DataInfo - sizeof(CountDataEntries) < CountDataEntries 00543 // 00544 // That is equivalent with: 00545 // DataEntry < DataInfo + sizeof(CountDataEntries) + CountDataEntries 00546 // 00547 // ( The condition (DataEntry < DataInfo) used in the previous versions 00548 // is always verified by this one ) 00549 // 00550 00551 00552 if (((PUCHAR)DataEntry < (PUCHAR)DataInfo + sizeof(CapturedDataInfo.CountDataEntries) + CapturedDataInfo.CountDataEntries) || 00553 ((((PUCHAR)RequestMessage) + CapturedRequestMessage.u1.s1.TotalLength) < (PUCHAR)DataEntry)) { 00554 00555 return STATUS_INVALID_PARAMETER; 00556 } 00557 } 00558 00559 } except( EXCEPTION_EXECUTE_HANDLER ) { 00560 00561 Status = GetExceptionCode(); 00562 00563 return Status; 00564 } 00565 00566 } else { 00567 00568 CapturedRequestMessage = *RequestMessage; 00569 00570 if (CapturedRequestMessage.u2.s2.DataInfoOffset != 0) { 00571 00572 PPORT_DATA_INFORMATION DataInfo; 00573 00574 DataInfo = (PPORT_DATA_INFORMATION)(((PUCHAR)RequestMessage) + CapturedRequestMessage.u2.s2.DataInfoOffset); 00575 00576 CapturedDataInfo = *DataInfo; 00577 } 00578 } 00579 00580 // 00581 // If the message type is an lpc request then say we need a callback. 00582 // Otherwise if it not an lpc request and it is not a kernel mode message 00583 // then it is an illegal parameter. A third case is if the type is 00584 // a kernel mode message in which case we make it look like an lpc request 00585 // but without the callback. 00586 // 00587 00588 if ((CapturedRequestMessage.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) == LPC_REQUEST) { 00589 00590 CallbackRequest = TRUE; 00591 00592 } else if ((CapturedRequestMessage.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) != 0) { 00593 00594 return STATUS_INVALID_PARAMETER; 00595 00596 } else { 00597 00598 CapturedRequestMessage.u2.s2.Type |= LPC_REQUEST; 00599 CallbackRequest = FALSE; 00600 } 00601 00602 // 00603 // Make sure DataLength is valid with respect to header size and total length 00604 // 00605 00606 if ((((CLONG)CapturedRequestMessage.u1.s1.DataLength) + sizeof( PORT_MESSAGE )) > 00607 ((CLONG)CapturedRequestMessage.u1.s1.TotalLength)) { 00608 00609 return STATUS_INVALID_PARAMETER; 00610 } 00611 00612 // 00613 // Reference the communication port object by handle. Return status if 00614 // unsuccessful. 00615 // 00616 00617 Status = LpcpReferencePortObject( PortHandle, 00618 0, 00619 PreviousMode, 00620 &PortObject ); 00621 00622 if (!NT_SUCCESS( Status )) { 00623 00624 return Status; 00625 } 00626 00627 // 00628 // Validate the message length 00629 // 00630 00631 if (((ULONG)CapturedRequestMessage.u1.s1.TotalLength > PortObject->MaxMessageLength) || 00632 ((ULONG)CapturedRequestMessage.u1.s1.TotalLength <= (ULONG)CapturedRequestMessage.u1.s1.DataLength)) { 00633 00634 ObDereferenceObject( PortObject ); 00635 00636 return STATUS_PORT_MESSAGE_TOO_LONG; 00637 } 00638 00639 // 00640 // Determine which port to queue the message to and get client 00641 // port context if client sending to server. Also validate 00642 // length of message being sent. 00643 // 00644 00645 // 00646 // Allocate and initialize the LPC message to send off 00647 // 00648 00649 LpcpAcquireLpcpLock(); 00650 00651 Msg = (PLPCP_MESSAGE)LpcpAllocateFromPortZone( CapturedRequestMessage.u1.s1.TotalLength ); 00652 00653 LpcpReleaseLpcpLock(); 00654 00655 if (Msg == NULL) { 00656 00657 ObDereferenceObject( PortObject ); 00658 00659 return STATUS_NO_MEMORY; 00660 } 00661 00662 MsgType = CapturedRequestMessage.u2.s2.Type; 00663 00664 // 00665 // Check if we need to do a callback 00666 // 00667 00668 if (CallbackRequest) { 00669 00670 // 00671 // Check for a valid request message id 00672 // 00673 00674 if (CapturedRequestMessage.MessageId == 0) { 00675 00676 LpcpFreeToPortZone( Msg, FALSE ); 00677 00678 ObDereferenceObject( PortObject ); 00679 00680 return STATUS_INVALID_PARAMETER; 00681 } 00682 00683 // 00684 // Translate the ClientId from the request into a 00685 // thread pointer. This is a referenced pointer to keep the thread 00686 // from evaporating out from under us. 00687 // 00688 00689 Status = PsLookupProcessThreadByCid( &CapturedRequestMessage.ClientId, 00690 NULL, 00691 &WakeupThread ); 00692 00693 if (!NT_SUCCESS( Status )) { 00694 00695 LpcpFreeToPortZone( Msg, FALSE ); 00696 00697 ObDereferenceObject( PortObject ); 00698 00699 return Status; 00700 } 00701 00702 // 00703 // Acquire the mutex that guards the LpcReplyMessage field of 00704 // the thread and get the pointer to the message that the thread 00705 // is waiting for a reply to. 00706 // 00707 00708 LpcpAcquireLpcpLock(); 00709 00710 // 00711 // See if the thread is waiting for a reply to the message 00712 // specified on this call. If not then a bogus message has been 00713 // specified, so release the mutex, dereference the thread 00714 // and return failure. 00715 // 00716 00717 if ((WakeupThread->LpcReplyMessageId != CapturedRequestMessage.MessageId) 00718 00719 || 00720 00721 ((WakeupThread->LpcReplyMessage != NULL) && 00722 (((PLPCP_MESSAGE)(WakeupThread->LpcReplyMessage))->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) != LPC_REQUEST)) { 00723 00724 LpcpPrint(( "%s Attempted CallBack Request to Thread %lx (%s)\n", 00725 PsGetCurrentProcess()->ImageFileName, 00726 WakeupThread, 00727 THREAD_TO_PROCESS( WakeupThread )->ImageFileName )); 00728 00729 LpcpPrint(( "failed. MessageId == %u Client Id: %x.%x\n", 00730 CapturedRequestMessage.MessageId, 00731 CapturedRequestMessage.ClientId.UniqueProcess, 00732 CapturedRequestMessage.ClientId.UniqueThread )); 00733 00734 LpcpPrint(( " Thread MessageId == %u Client Id: %x.%x\n", 00735 WakeupThread->LpcReplyMessageId, 00736 WakeupThread->Cid.UniqueProcess, 00737 WakeupThread->Cid.UniqueThread )); 00738 00739 #if DBG 00740 if (LpcpStopOnReplyMismatch) { 00741 00742 DbgBreakPoint(); 00743 } 00744 #endif 00745 00746 LpcpFreeToPortZone( Msg, TRUE ); 00747 00748 LpcpReleaseLpcpLock(); 00749 00750 ObDereferenceObject( WakeupThread ); 00751 ObDereferenceObject( PortObject ); 00752 00753 return STATUS_REPLY_MESSAGE_MISMATCH; 00754 } 00755 00756 // 00757 // Copy over the text of the message 00758 // 00759 00760 try { 00761 00762 LpcpMoveMessage( &Msg->Request, 00763 &CapturedRequestMessage, 00764 (RequestMessage + 1), 00765 MsgType, 00766 &CurrentThread->Cid ); 00767 00768 if (CapturedRequestMessage.u2.s2.DataInfoOffset != 0) { 00769 00770 PPORT_DATA_INFORMATION DataInfo; 00771 00772 DataInfo = (PPORT_DATA_INFORMATION)(((PUCHAR)RequestMessage) + CapturedRequestMessage.u2.s2.DataInfoOffset); 00773 00774 if ( DataInfo->CountDataEntries != CapturedDataInfo.CountDataEntries ) { 00775 00776 Status = STATUS_INVALID_PARAMETER; 00777 } 00778 } 00779 } except( EXCEPTION_EXECUTE_HANDLER ) { 00780 00781 Status = GetExceptionCode(); 00782 } 00783 00784 if (!NT_SUCCESS( Status )) { 00785 00786 LpcpFreeToPortZone( Msg, FALSE ); 00787 00788 LpcpReleaseLpcpLock(); 00789 00790 ObDereferenceObject( WakeupThread ); 00791 ObDereferenceObject( PortObject ); 00792 00793 return Status; 00794 } 00795 00796 // 00797 // Under the protect of the global lock we'll get everything 00798 // ready for the callback 00799 // 00800 00801 QueuePort = NULL; 00802 Msg->PortContext = NULL; 00803 00804 if ((PortObject->Flags & PORT_TYPE) == SERVER_CONNECTION_PORT) { 00805 00806 RundownPort = PortObject; 00807 00808 } else { 00809 00810 RundownPort = PortObject->ConnectedPort; 00811 00812 if (RundownPort == NULL) { 00813 00814 LpcpFreeToPortZone( Msg, TRUE ); 00815 00816 LpcpReleaseLpcpLock(); 00817 00818 ObDereferenceObject( WakeupThread ); 00819 ObDereferenceObject( PortObject ); 00820 00821 return STATUS_PORT_DISCONNECTED; 00822 } 00823 00824 if ((PortObject->Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) { 00825 00826 Msg->PortContext = RundownPort->PortContext; 00827 } 00828 } 00829 00830 Msg->Request.CallbackId = LpcpGenerateCallbackId(); 00831 00832 LpcpTrace(( "%s CallBack Request (%s) Msg %lx (%u.%u) [%08x %08x %08x %08x] to Thread %lx (%s)\n", 00833 PsGetCurrentProcess()->ImageFileName, 00834 LpcpMessageTypeName[ Msg->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE ], 00835 Msg, 00836 Msg->Request.MessageId, 00837 Msg->Request.CallbackId, 00838 *((PULONG)(Msg+1)+0), 00839 *((PULONG)(Msg+1)+1), 00840 *((PULONG)(Msg+1)+2), 00841 *((PULONG)(Msg+1)+3), 00842 WakeupThread, 00843 THREAD_TO_PROCESS( WakeupThread )->ImageFileName )); 00844 00845 // 00846 // Add an extra reference so LpcExitThread does not evaporate 00847 // the pointer before we get to the wait below 00848 // 00849 00850 ObReferenceObject( WakeupThread ); 00851 00852 Msg->RepliedToThread = WakeupThread; 00853 00854 WakeupThread->LpcReplyMessageId = 0; 00855 WakeupThread->LpcReplyMessage = (PVOID)Msg; 00856 00857 // 00858 // Remove the thread from the reply rundown list as we are sending a callback 00859 // 00860 00861 if (!IsListEmpty( &WakeupThread->LpcReplyChain )) { 00862 00863 RemoveEntryList( &WakeupThread->LpcReplyChain ); 00864 00865 InitializeListHead( &WakeupThread->LpcReplyChain ); 00866 } 00867 00868 CurrentThread->LpcReplyMessageId = Msg->Request.MessageId; 00869 CurrentThread->LpcReplyMessage = NULL; 00870 00871 InsertTailList( &RundownPort->LpcReplyChainHead, &CurrentThread->LpcReplyChain ); 00872 00873 LpcpReleaseLpcpLock(); 00874 00875 // 00876 // Wake up the thread that is waiting for an answer to its request 00877 // inside of NtRequestWaitReplyPort or NtReplyWaitReplyPort 00878 // 00879 00880 ReleaseSemaphore = &WakeupThread->LpcReplySemaphore; 00881 00882 } else { 00883 00884 // 00885 // A callback is not required, so continue setting up the 00886 // lpc message 00887 // 00888 00889 try { 00890 00891 LpcpMoveMessage( &Msg->Request, 00892 &CapturedRequestMessage, 00893 (RequestMessage + 1), 00894 MsgType, 00895 &CurrentThread->Cid ); 00896 00897 if (CapturedRequestMessage.u2.s2.DataInfoOffset != 0) { 00898 00899 PPORT_DATA_INFORMATION DataInfo; 00900 00901 DataInfo = (PPORT_DATA_INFORMATION)(((PUCHAR)RequestMessage) + CapturedRequestMessage.u2.s2.DataInfoOffset); 00902 00903 if ( DataInfo->CountDataEntries != CapturedDataInfo.CountDataEntries ) { 00904 00905 LpcpFreeToPortZone( Msg, FALSE ); 00906 00907 ObDereferenceObject( PortObject ); 00908 00909 return STATUS_INVALID_PARAMETER; 00910 } 00911 } 00912 } except( EXCEPTION_EXECUTE_HANDLER ) { 00913 00914 LpcpFreeToPortZone( Msg, FALSE ); 00915 00916 ObDereferenceObject( PortObject ); 00917 00918 return GetExceptionCode(); 00919 } 00920 00921 // 00922 // Acquire the global Lpc mutex that guards the LpcReplyMessage 00923 // field of the thread and the request message queue. Stamp the 00924 // request message with a serial number, insert the message at 00925 // the tail of the request message queue and remember the address 00926 // of the message in the LpcReplyMessage field for the current thread. 00927 // 00928 // **** does this also need to be done with APC's disabled? 00929 // 00930 00931 LpcpAcquireLpcpLock(); 00932 00933 Msg->PortContext = NULL; 00934 00935 if ((PortObject->Flags & PORT_TYPE) != SERVER_CONNECTION_PORT) { 00936 00937 QueuePort = PortObject->ConnectedPort; 00938 00939 if (QueuePort == NULL) { 00940 00941 LpcpFreeToPortZone( Msg, TRUE ); 00942 00943 LpcpReleaseLpcpLock(); 00944 00945 ObDereferenceObject( PortObject ); 00946 00947 return STATUS_PORT_DISCONNECTED; 00948 } 00949 00950 RundownPort = QueuePort; 00951 00952 if ((PortObject->Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) { 00953 00954 Msg->PortContext = QueuePort->PortContext; 00955 QueuePort = PortObject->ConnectionPort; 00956 00957 } else if ((PortObject->Flags & PORT_TYPE) != SERVER_COMMUNICATION_PORT) { 00958 00959 QueuePort = PortObject->ConnectionPort; 00960 } 00961 00962 } else { 00963 00964 QueuePort = PortObject; 00965 RundownPort = PortObject; 00966 } 00967 00968 // 00969 // Stamp the request message with a serial number, insert the message 00970 // at the tail of the request message queue 00971 // 00972 00973 Msg->RepliedToThread = NULL; 00974 Msg->Request.MessageId = LpcpGenerateMessageId(); 00975 Msg->Request.CallbackId = 0; 00976 00977 CurrentThread->LpcReplyMessageId = Msg->Request.MessageId; 00978 CurrentThread->LpcReplyMessage = NULL; 00979 00980 InsertTailList( &QueuePort->MsgQueue.ReceiveHead, &Msg->Entry ); 00981 InsertTailList( &RundownPort->LpcReplyChainHead, &CurrentThread->LpcReplyChain ); 00982 00983 LpcpTrace(( "%s Send Request (%s) Msg %lx (%u) [%08x %08x %08x %08x] to Port %lx (%s)\n", 00984 PsGetCurrentProcess()->ImageFileName, 00985 LpcpMessageTypeName[ Msg->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE ], 00986 Msg, 00987 Msg->Request.MessageId, 00988 *((PULONG)(Msg+1)+0), 00989 *((PULONG)(Msg+1)+1), 00990 *((PULONG)(Msg+1)+2), 00991 *((PULONG)(Msg+1)+3), 00992 QueuePort, 00993 LpcpGetCreatorName( QueuePort ))); 00994 00995 LpcpReleaseLpcpLock(); 00996 00997 // 00998 // Increment the request message queue semaphore by one for 00999 // the newly inserted request message. 01000 // 01001 01002 ReleaseSemaphore = QueuePort->MsgQueue.Semaphore; 01003 01004 // 01005 // If port is waitable then set the event that someone could 01006 // be waiting on 01007 // 01008 01009 if ( QueuePort->Flags & PORT_WAITABLE ) { 01010 01011 KeSetEvent( &QueuePort->WaitEvent, 01012 LPC_RELEASE_WAIT_INCREMENT, 01013 FALSE ); 01014 } 01015 } 01016 01017 // 01018 // At this point we've enqueued our request and if necessary 01019 // set ourselves up for the callback or reply. 01020 // 01021 // So now wake up the other end 01022 // 01023 01024 Status = KeReleaseSemaphore( ReleaseSemaphore, 01025 1, 01026 1, 01027 FALSE ); 01028 01029 if (CallbackRequest) { 01030 01031 ObDereferenceObject( WakeupThread ); 01032 } 01033 01034 // 01035 // And wait for a reply 01036 // 01037 01038 Status = KeWaitForSingleObject( &CurrentThread->LpcReplySemaphore, 01039 WrLpcReply, 01040 PreviousMode, 01041 FALSE, 01042 NULL ); 01043 01044 if (Status == STATUS_USER_APC) { 01045 01046 // 01047 // if the semaphore is signaled, then clear it 01048 // 01049 01050 if (KeReadStateSemaphore( &CurrentThread->LpcReplySemaphore )) { 01051 01052 KeWaitForSingleObject( &CurrentThread->LpcReplySemaphore, 01053 WrExecutive, 01054 KernelMode, 01055 FALSE, 01056 NULL ); 01057 01058 Status = STATUS_SUCCESS; 01059 } 01060 } 01061 01062 // 01063 // Acquire the LPC mutex. Remove the reply message from the current thread 01064 // 01065 01066 LpcpAcquireLpcpLock(); 01067 01068 Msg = CurrentThread->LpcReplyMessage; 01069 01070 CurrentThread->LpcReplyMessage = NULL; 01071 CurrentThread->LpcReplyMessageId = 0; 01072 01073 // 01074 // Remove the thread from the reply rundown list in case we did not wakeup due to 01075 // a reply 01076 // 01077 01078 if (!IsListEmpty( &CurrentThread->LpcReplyChain )) { 01079 01080 RemoveEntryList( &CurrentThread->LpcReplyChain ); 01081 01082 InitializeListHead( &CurrentThread->LpcReplyChain ); 01083 } 01084 01085 #if DBG 01086 if (Status == STATUS_SUCCESS && Msg != NULL) { 01087 01088 LpcpTrace(( "%s Got Reply Msg %lx (%u) [%08x %08x %08x %08x] for Thread %lx (%s)\n", 01089 PsGetCurrentProcess()->ImageFileName, 01090 Msg, 01091 Msg->Request.MessageId, 01092 *((PULONG)(Msg+1)+0), 01093 *((PULONG)(Msg+1)+1), 01094 *((PULONG)(Msg+1)+2), 01095 *((PULONG)(Msg+1)+3), 01096 CurrentThread, 01097 THREAD_TO_PROCESS( CurrentThread )->ImageFileName )); 01098 01099 if (!IsListEmpty( &Msg->Entry )) { 01100 01101 LpcpTrace(( "Reply Msg %lx has non-empty list entry\n", Msg )); 01102 } 01103 } 01104 #endif 01105 01106 LpcpReleaseLpcpLock(); 01107 01108 // 01109 // If the wait succeeded, copy the reply to the reply buffer. 01110 // 01111 01112 if (Status == STATUS_SUCCESS) { 01113 01114 if (Msg != NULL) { 01115 01116 try { 01117 01118 LpcpMoveMessage( ReplyMessage, 01119 &Msg->Request, 01120 (&Msg->Request) + 1, 01121 0, 01122 NULL ); 01123 01124 } except( EXCEPTION_EXECUTE_HANDLER ) { 01125 01126 Status = GetExceptionCode(); 01127 } 01128 01129 // 01130 // Acquire the LPC mutex and decrement the reference count for the 01131 // message. If the reference count goes to zero the message will be 01132 // deleted. 01133 // 01134 01135 if (((Msg->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) == LPC_REQUEST) && 01136 (Msg->Request.u2.s2.DataInfoOffset != 0)) { 01137 01138 LpcpSaveDataInfoMessage( PortObject, Msg ); 01139 01140 } else { 01141 01142 LpcpFreeToPortZone( Msg, FALSE ); 01143 } 01144 01145 } else { 01146 01147 Status = STATUS_LPC_REPLY_LOST; 01148 } 01149 01150 } else { 01151 01152 // 01153 // Wait failed, acquire the LPC mutex and free the message. 01154 // 01155 01156 LpcpAcquireLpcpLock(); 01157 01158 LpcpTrace(( "%s NtRequestWaitReply wait failed - Status == %lx\n", 01159 PsGetCurrentProcess()->ImageFileName, 01160 Status )); 01161 01162 if (Msg != NULL) { 01163 01164 LpcpFreeToPortZone( Msg, TRUE ); 01165 } 01166 01167 LpcpReleaseLpcpLock(); 01168 } 01169 01170 ObDereferenceObject( PortObject ); 01171 01172 // 01173 // And return to our caller 01174 // 01175 01176 return Status; 01177 }


Generated on Sat May 15 19:44:34 2004 for test by doxygen 1.3.7