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

lpcreply.c File Reference

#include "lpcp.h"

Go to the source code of this file.

Functions

NTSTATUS LpcpCopyRequestData (IN BOOLEAN WriteToMessageData, IN HANDLE PortHandle, IN PPORT_MESSAGE Message, IN ULONG DataEntryIndex, IN PVOID Buffer, IN ULONG BufferSize, OUT PULONG NumberOfBytesCopied OPTIONAL)
NTSTATUS NtReplyPort (IN HANDLE PortHandle, IN PPORT_MESSAGE ReplyMessage)
NTSTATUS NtReplyWaitReplyPort (IN HANDLE PortHandle, IN OUT PPORT_MESSAGE ReplyMessage)
NTSTATUS NtReadRequestData (IN HANDLE PortHandle, IN PPORT_MESSAGE Message, IN ULONG DataEntryIndex, OUT PVOID Buffer, IN ULONG BufferSize, OUT PULONG NumberOfBytesRead OPTIONAL)
NTSTATUS NtWriteRequestData (IN HANDLE PortHandle, IN PPORT_MESSAGE Message, IN ULONG DataEntryIndex, IN PVOID Buffer, IN ULONG BufferSize, OUT PULONG NumberOfBytesWritten OPTIONAL)


Function Documentation

NTSTATUS LpcpCopyRequestData IN BOOLEAN  WriteToMessageData,
IN HANDLE  PortHandle,
IN PPORT_MESSAGE  Message,
IN ULONG  DataEntryIndex,
IN PVOID  Buffer,
IN ULONG  BufferSize,
OUT PULONG NumberOfBytesCopied  OPTIONAL
 

Definition at line 915 of file lpcreply.c.

References Buffer, BufferSize, ClientThread(), EXCEPTION_EXECUTE_HANDLER, KernelMode, KPROCESSOR_MODE, LpcpAcquireLpcpLock, LpcpFindDataInfoMessage(), LpcpReferencePortObject, LpcpReleaseLpcpLock, LpcpSaveThread, MmCopyVirtualMemory(), NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, PAGED_CODE, PortHandle, ProbeForRead, ProbeForWrite(), ProbeForWriteUlong, PsGetCurrentProcess, PsLookupProcessThreadByCid(), _LPCP_MESSAGE::Request, Status, and THREAD_TO_PROCESS.

Referenced by NtReadRequestData(), and NtWriteRequestData().

00927 : 00928 00929 This routine will copy data to or from the user supplied buffer and the 00930 port message data information buffer 00931 00932 Arguments: 00933 00934 WriteToMessageData - TRUE if the data is to be copied from the user buffer 00935 to the message and FALSE otherwise 00936 00937 PortHandle - Supplies the port into which the message is being manipulated 00938 00939 Message - Supplies the message that we are trying to manipulate 00940 00941 DataEntryIndex - Supplies the index of the port data entry in the 00942 preceeding message that we are transfering 00943 00944 Buffer - Supplies the location into which the data is to be transfered 00945 00946 BufferSize - Supplies the size, in bytes, of the preceeding buffer 00947 00948 NumberOfBytesRead - Optionally returns the number of bytes transfered from 00949 the buffer 00950 00951 Return Value: 00952 00953 NTSTATUS - An appropriate status value 00954 00955 --*/ 00956 00957 { 00958 KPROCESSOR_MODE PreviousMode; 00959 PLPCP_PORT_OBJECT PortObject; 00960 PLPCP_MESSAGE Msg; 00961 PLIST_ENTRY Head, Next; 00962 NTSTATUS Status; 00963 PETHREAD ClientThread; 00964 PPORT_DATA_INFORMATION DataInfo; 00965 PPORT_DATA_ENTRY DataEntry; 00966 PORT_MESSAGE CapturedMessage; 00967 PORT_DATA_INFORMATION CapturedDataInfo; 00968 PORT_DATA_ENTRY CapturedDataEntry; 00969 ULONG BytesCopied; 00970 00971 PAGED_CODE(); 00972 00973 // 00974 // Get previous processor mode and probe output arguments if necessary. 00975 // 00976 00977 PreviousMode = KeGetPreviousMode(); 00978 00979 if (PreviousMode != KernelMode) { 00980 00981 try { 00982 00983 // 00984 // We are either reading or writing the user buffer 00985 // 00986 00987 if (WriteToMessageData) { 00988 00989 ProbeForRead( Buffer, 00990 BufferSize, 00991 1 ); 00992 00993 } else { 00994 00995 ProbeForWrite( Buffer, 00996 BufferSize, 00997 1 ); 00998 } 00999 01000 ProbeForRead( Message, 01001 sizeof( *Message ), 01002 sizeof( ULONG )); 01003 01004 CapturedMessage = *Message; 01005 01006 if (ARGUMENT_PRESENT( NumberOfBytesCopied )) { 01007 01008 ProbeForWriteUlong( NumberOfBytesCopied ); 01009 } 01010 01011 } except( EXCEPTION_EXECUTE_HANDLER ) { 01012 01013 return GetExceptionCode(); 01014 } 01015 01016 } else { 01017 01018 CapturedMessage = *Message; 01019 } 01020 01021 // 01022 // The message better have at least one data entry 01023 // 01024 01025 if (CapturedMessage.u2.s2.DataInfoOffset == 0) { 01026 01027 return STATUS_INVALID_PARAMETER; 01028 } 01029 01030 // 01031 // Reference the port object by handle 01032 // 01033 01034 Status = LpcpReferencePortObject( PortHandle, 01035 0, 01036 PreviousMode, 01037 &PortObject ); 01038 01039 if (!NT_SUCCESS( Status )) { 01040 01041 return Status; 01042 } 01043 01044 LpcpSaveThread (PortObject); 01045 01046 // 01047 // Translate the ClientId from the connection request into a 01048 // thread pointer. This is a referenced pointer to keep the thread 01049 // from evaporating out from under us. 01050 // 01051 01052 Status = PsLookupProcessThreadByCid( &CapturedMessage.ClientId, 01053 NULL, 01054 &ClientThread ); 01055 01056 if (!NT_SUCCESS( Status )) { 01057 01058 ObDereferenceObject( PortObject ); 01059 01060 return Status; 01061 } 01062 01063 // 01064 // Acquire the mutex that guards the LpcReplyMessage field of 01065 // the thread and get the pointer to the message that the thread 01066 // is waiting for a reply to. 01067 // 01068 01069 LpcpAcquireLpcpLock(); 01070 01071 // 01072 // See if the thread is waiting for a reply to the message 01073 // specified on this call. If not then a bogus message 01074 // has been specified, so release the mutex, dereference the thread 01075 // and return failure. 01076 // 01077 01078 if (ClientThread->LpcReplyMessageId != CapturedMessage.MessageId) { 01079 01080 Status = STATUS_REPLY_MESSAGE_MISMATCH; 01081 01082 } else { 01083 01084 Status = STATUS_INVALID_PARAMETER; 01085 01086 Msg = LpcpFindDataInfoMessage( PortObject, 01087 CapturedMessage.MessageId, 01088 CapturedMessage.CallbackId ); 01089 01090 if (Msg != NULL) { 01091 01092 DataInfo = (PPORT_DATA_INFORMATION)((PUCHAR)&Msg->Request + 01093 Msg->Request.u2.s2.DataInfoOffset); 01094 01095 // 01096 // Make sure the caller isn't asking for an index beyond what's 01097 // in the message 01098 // 01099 01100 if (DataInfo->CountDataEntries > DataEntryIndex) { 01101 01102 DataEntry = &DataInfo->DataEntries[ DataEntryIndex ]; 01103 CapturedDataEntry = *DataEntry; 01104 01105 if (CapturedDataEntry.Size >= BufferSize) { 01106 01107 Status = STATUS_SUCCESS; 01108 } 01109 } 01110 } 01111 } 01112 01113 if (!NT_SUCCESS( Status )) { 01114 01115 LpcpReleaseLpcpLock(); 01116 01117 ObDereferenceObject( ClientThread ); 01118 ObDereferenceObject( PortObject ); 01119 01120 return Status; 01121 } 01122 01123 // 01124 // Release the mutex that guards the LpcReplyMessage field 01125 // 01126 01127 LpcpReleaseLpcpLock(); 01128 01129 // 01130 // Copy the message data 01131 // 01132 01133 if (WriteToMessageData) { 01134 01135 Status = MmCopyVirtualMemory( PsGetCurrentProcess(), 01136 Buffer, 01137 THREAD_TO_PROCESS( ClientThread ), 01138 CapturedDataEntry.Base, 01139 BufferSize, 01140 PreviousMode, 01141 &BytesCopied ); 01142 01143 } else { 01144 01145 Status = MmCopyVirtualMemory( THREAD_TO_PROCESS( ClientThread ), 01146 CapturedDataEntry.Base, 01147 PsGetCurrentProcess(), 01148 Buffer, 01149 BufferSize, 01150 PreviousMode, 01151 &BytesCopied ); 01152 } 01153 01154 if (ARGUMENT_PRESENT( NumberOfBytesCopied )) { 01155 01156 try { 01157 01158 *NumberOfBytesCopied = BytesCopied; 01159 01160 } except( EXCEPTION_EXECUTE_HANDLER ) { 01161 01162 NOTHING; 01163 } 01164 } 01165 01166 // 01167 // Dereference client thread and return the system service status. 01168 // 01169 01170 ObDereferenceObject( ClientThread ); 01171 ObDereferenceObject( PortObject ); 01172 01173 return Status; 01174 } }

NTSTATUS NtReadRequestData IN HANDLE  PortHandle,
IN PPORT_MESSAGE  Message,
IN ULONG  DataEntryIndex,
OUT PVOID  Buffer,
IN ULONG  BufferSize,
OUT PULONG NumberOfBytesRead  OPTIONAL
 

Definition at line 807 of file lpcreply.c.

References Buffer, BufferSize, FALSE, LpcpCopyRequestData(), PAGED_CODE, and PortHandle.

00818 : 00819 00820 This routine is used to copy data from a port message into the user 00821 supplied buffer. 00822 00823 Arguments: 00824 00825 PortHandle - Supplies the port from which the message is being read 00826 00827 Message - Supplies the message that we are trying to read 00828 00829 DataEntryIndex - Supplies the index of the port data entry in the 00830 preceeding message that we are reading 00831 00832 Buffer - Supplies the location into which the data is to be read 00833 00834 BufferSize - Supplies the size, in bytes, of the preceeding buffer 00835 00836 NumberOfBytesRead - Optionally returns the number of bytes read into 00837 the buffer 00838 00839 Return Value: 00840 00841 NTSTATUS - An appropriate status value 00842 00843 --*/ 00844 00845 { 00846 PAGED_CODE(); 00847 00848 return LpcpCopyRequestData( FALSE, 00849 PortHandle, 00850 Message, 00851 DataEntryIndex, 00852 Buffer, 00853 BufferSize, 00854 NumberOfBytesRead ); 00855 }

NTSTATUS NtReplyPort IN HANDLE  PortHandle,
IN PPORT_MESSAGE  ReplyMessage
 

Definition at line 44 of file lpcreply.c.

References _ETHREAD::Cid, EXCEPTION_EXECUTE_HANDLER, FALSE, KeReleaseSemaphore(), KernelMode, KPROCESSOR_MODE, L, _ETHREAD::LpcExitThreadCalled, LpcpAcquireLpcpLock, LpcpAllocateFromPortZone(), LpcpFreeDataInfoMessage(), LpcpFreeToPortZone(), LpcpMoveMessage(), LpcpPrint, LpcpReferencePortObject, LpcpReleaseLpcpLock, LpcpSaveThread, LpcpTrace, _ETHREAD::LpcReceivedMessageId, _ETHREAD::LpcReceivedMsgIdValid, _ETHREAD::LpcReplyChain, _ETHREAD::LpcReplyMessage, _ETHREAD::LpcReplyMessageId, _ETHREAD::LpcReplySemaphore, _LPCP_PORT_OBJECT::MaxMessageLength, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObject, PAGED_CODE, PortHandle, ProbeForRead, PsGetCurrentProcess, PsGetCurrentThread, PsLookupProcessThreadByCid(), ReplyMessage(), _LPCP_MESSAGE::Request, Status, THREAD_TO_PROCESS, and TRUE.

Referenced by DbgSsHandleKmApiMsg(), DbgSspSrvApiLoop(), ReplyHardError(), RtlpLpcWorkerThread(), SrvEndTask(), UdbgTest1(), UdbgTest2(), and UserHardErrorEx().

00051 : 00052 00053 A client and server process can send a reply to a previous request 00054 message with the NtReplyPort service: 00055 00056 The Type field of the message is set to LPC_REPLY by the service. If the 00057 MapInfoOffset field of the reply message is non-zero, then the 00058 PORT_MAP_INFORMATION structure it points to will be processed and the 00059 relevant pages in the caller's address space will be unmapped. 00060 00061 The ClientId and MessageId fields of the ReplyMessage structure are used 00062 to identify the thread waiting for this reply. If the target thread is 00063 in fact waiting for this reply message, then the reply message is copied 00064 into the thread's message buffer and the thread's wait is satisfied. 00065 00066 If the thread is not waiting for a reply or is waiting for a reply to 00067 some other MessageId, then the message is placed in the message queue of 00068 the port that is connected to the communication port specified by the 00069 PortHandle parameter and the Type field of the message is set to 00070 LPC_LOST_REPLY. 00071 00072 Arguments: 00073 00074 PortHandle - Specifies the handle of the communication port that the 00075 original message was received from. 00076 00077 ReplyMessage - Specifies a pointer to the reply message to be sent. 00078 The ClientId and MessageId fields determine which thread will 00079 get the reply. 00080 00081 Return Value: 00082 00083 Status code that indicates whether or not the operation was 00084 successful. 00085 00086 --*/ 00087 00088 { 00089 KPROCESSOR_MODE PreviousMode; 00090 PLPCP_PORT_OBJECT PortObject; 00091 PORT_MESSAGE CapturedReplyMessage; 00092 NTSTATUS Status; 00093 PLPCP_MESSAGE Msg; 00094 PETHREAD CurrentThread; 00095 PETHREAD WakeupThread; 00096 00097 PAGED_CODE(); 00098 00099 CurrentThread = PsGetCurrentThread(); 00100 00101 // 00102 // Get previous processor mode and probe output arguments if necessary. 00103 // 00104 00105 PreviousMode = KeGetPreviousMode(); 00106 00107 if (PreviousMode != KernelMode) { 00108 00109 try { 00110 00111 ProbeForRead( ReplyMessage, 00112 sizeof( *ReplyMessage ), 00113 sizeof( ULONG )); 00114 00115 CapturedReplyMessage = *ReplyMessage; 00116 00117 } except( EXCEPTION_EXECUTE_HANDLER ) { 00118 00119 return GetExceptionCode(); 00120 } 00121 00122 } else { 00123 00124 CapturedReplyMessage = *ReplyMessage; 00125 } 00126 00127 // 00128 // Make sure DataLength is valid with respect to header size and total 00129 // length 00130 // 00131 00132 if ((((CLONG)CapturedReplyMessage.u1.s1.DataLength) + sizeof( PORT_MESSAGE )) > 00133 ((CLONG)CapturedReplyMessage.u1.s1.TotalLength)) { 00134 00135 return STATUS_INVALID_PARAMETER; 00136 } 00137 00138 // 00139 // Make sure the user didn't give us a bogus reply message id 00140 // 00141 00142 if (CapturedReplyMessage.MessageId == 0) { 00143 00144 return STATUS_INVALID_PARAMETER; 00145 } 00146 00147 // 00148 // Reference the port object by handle 00149 // 00150 00151 Status = LpcpReferencePortObject( PortHandle, 00152 0, 00153 PreviousMode, 00154 &PortObject ); 00155 00156 if (!NT_SUCCESS( Status )) { 00157 00158 return Status; 00159 } 00160 00161 LpcpSaveThread (PortObject); 00162 00163 // 00164 // Validate the message length 00165 // 00166 00167 if (((ULONG)CapturedReplyMessage.u1.s1.TotalLength > PortObject->MaxMessageLength) || 00168 ((ULONG)CapturedReplyMessage.u1.s1.TotalLength <= (ULONG)CapturedReplyMessage.u1.s1.DataLength)) { 00169 00170 ObDereferenceObject( PortObject ); 00171 00172 return STATUS_PORT_MESSAGE_TOO_LONG; 00173 } 00174 00175 // 00176 // Translate the ClientId from the connection request into a thread 00177 // pointer. This is a referenced pointer to keep the thread from 00178 // evaporating out from under us. 00179 // 00180 00181 Status = PsLookupProcessThreadByCid( &CapturedReplyMessage.ClientId, 00182 NULL, 00183 &WakeupThread ); 00184 00185 if (!NT_SUCCESS( Status )) { 00186 00187 ObDereferenceObject( PortObject ); 00188 00189 return Status; 00190 } 00191 00192 // 00193 // Acquire the mutex that guards the LpcReplyMessage field of the thread 00194 // and get the pointer to the message that the thread is waiting for a 00195 // reply to. 00196 // 00197 00198 LpcpAcquireLpcpLock(); 00199 00200 Msg = (PLPCP_MESSAGE)LpcpAllocateFromPortZone( CapturedReplyMessage.u1.s1.TotalLength ); 00201 00202 if (Msg == NULL) { 00203 00204 LpcpReleaseLpcpLock(); 00205 00206 ObDereferenceObject( WakeupThread ); 00207 ObDereferenceObject( PortObject ); 00208 00209 return STATUS_NO_MEMORY; 00210 } 00211 00212 // 00213 // See if the thread is waiting for a reply to the message specified on 00214 // this call. If not then a bogus message has been specified, so 00215 // release the mutex, dereference the thread and return failure. 00216 // 00217 // We also fail this request if the caller isn't replying to a request 00218 // message. For example, if the caller is replying to a connection 00219 // request 00220 // 00221 00222 if ((WakeupThread->LpcReplyMessageId != CapturedReplyMessage.MessageId) 00223 00224 || 00225 00226 ((WakeupThread->LpcReplyMessage != NULL) && 00227 (((PLPCP_MESSAGE)(WakeupThread->LpcReplyMessage))->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) != LPC_REQUEST)) { 00228 00229 LpcpPrint(( "%s Attempted reply to Thread %lx (%s)\n", 00230 PsGetCurrentProcess()->ImageFileName, 00231 WakeupThread, 00232 THREAD_TO_PROCESS( WakeupThread )->ImageFileName )); 00233 00234 LpcpPrint(( "failed. MessageId == %u Client Id: %x.%x\n", 00235 CapturedReplyMessage.MessageId, 00236 CapturedReplyMessage.ClientId.UniqueProcess, 00237 CapturedReplyMessage.ClientId.UniqueThread )); 00238 00239 LpcpPrint(( " Thread MessageId == %u Client Id: %x.%x\n", 00240 WakeupThread->LpcReplyMessageId, 00241 WakeupThread->Cid.UniqueProcess, 00242 WakeupThread->Cid.UniqueThread )); 00243 00244 #if DBG 00245 if (LpcpStopOnReplyMismatch) { 00246 00247 DbgBreakPoint(); 00248 } 00249 #endif 00250 00251 LpcpFreeToPortZone( Msg, TRUE ); 00252 00253 LpcpReleaseLpcpLock(); 00254 00255 ObDereferenceObject( WakeupThread ); 00256 ObDereferenceObject( PortObject ); 00257 00258 return STATUS_REPLY_MESSAGE_MISMATCH; 00259 } 00260 00261 // 00262 // Copy the reply message to the request message buffer. Do this before 00263 // we actually fiddle with the wakeup threads fields. Otherwise we 00264 // could mess up its state 00265 // 00266 00267 try { 00268 00269 LpcpMoveMessage( &Msg->Request, 00270 &CapturedReplyMessage, 00271 (ReplyMessage + 1), 00272 LPC_REPLY, 00273 NULL ); 00274 00275 } except( EXCEPTION_EXECUTE_HANDLER ) { 00276 00277 LpcpFreeToPortZone( Msg, TRUE ); 00278 00279 LpcpReleaseLpcpLock(); 00280 00281 ObDereferenceObject( WakeupThread ); 00282 ObDereferenceObject( PortObject ); 00283 00284 return (Status = GetExceptionCode()); 00285 } 00286 00287 // 00288 // At this point we know the thread is waiting for our reply 00289 // 00290 00291 LpcpTrace(( "%s Sending Reply Msg %lx (%u, %x) [%08x %08x %08x %08x] to Thread %lx (%s)\n", 00292 PsGetCurrentProcess()->ImageFileName, 00293 Msg, 00294 CapturedReplyMessage.MessageId, 00295 CapturedReplyMessage.u2.s2.DataInfoOffset, 00296 *((PULONG)(Msg+1)+0), 00297 *((PULONG)(Msg+1)+1), 00298 *((PULONG)(Msg+1)+2), 00299 *((PULONG)(Msg+1)+3), 00300 WakeupThread, 00301 THREAD_TO_PROCESS( WakeupThread )->ImageFileName )); 00302 00303 // 00304 // Locate and free the messsage from the port. This call use to 00305 // test for (CapturedReplyMessage.u2.s2.DataInfoOffset != 0) as a 00306 // prerequisite for doing the call. 00307 // 00308 00309 LpcpFreeDataInfoMessage( PortObject, 00310 CapturedReplyMessage.MessageId, 00311 CapturedReplyMessage.CallbackId ); 00312 00313 // 00314 // Add an extra reference so LpcExitThread does not evaporate the 00315 // pointer before we get to the wait below 00316 // 00317 00318 ObReferenceObject( WakeupThread ); 00319 00320 // 00321 // Release the mutex that guards the LpcReplyMessage field after marking 00322 // message as being replied to. 00323 // 00324 00325 Msg->RepliedToThread = WakeupThread; 00326 00327 WakeupThread->LpcReplyMessageId = 0; 00328 WakeupThread->LpcReplyMessage = (PVOID)Msg; 00329 00330 // 00331 // Remove the thread from the reply rundown list as we are sending the 00332 // reply. 00333 // 00334 00335 if (!WakeupThread->LpcExitThreadCalled && !IsListEmpty( &WakeupThread->LpcReplyChain )) { 00336 00337 RemoveEntryList( &WakeupThread->LpcReplyChain ); 00338 00339 InitializeListHead( &WakeupThread->LpcReplyChain ); 00340 } 00341 00342 if ((CurrentThread->LpcReceivedMsgIdValid) && 00343 (CurrentThread->LpcReceivedMessageId == CapturedReplyMessage.MessageId)) { 00344 00345 CurrentThread->LpcReceivedMessageId = 0; 00346 CurrentThread->LpcReceivedMsgIdValid = FALSE; 00347 } 00348 00349 LpcpReleaseLpcpLock(); 00350 00351 // 00352 // Wake up the thread that is waiting for an answer to its request 00353 // inside of NtRequestWaitReplyPort or NtReplyWaitReplyPort. That 00354 // will dereference itself when it wakes up. 00355 // 00356 00357 KeReleaseSemaphore( &WakeupThread->LpcReplySemaphore, 00358 0, 00359 1L, 00360 FALSE ); 00361 00362 ObDereferenceObject( WakeupThread ); 00363 00364 // 00365 // Dereference port object and return the system service status. 00366 // 00367 00368 ObDereferenceObject( PortObject ); 00369 00370 return Status; 00371 }

NTSTATUS NtReplyWaitReplyPort IN HANDLE  PortHandle,
IN OUT PPORT_MESSAGE  ReplyMessage
 

Definition at line 375 of file lpcreply.c.

References _ETHREAD::Cid, EXCEPTION_EXECUTE_HANDLER, Executive, FALSE, KeReadStateSemaphore(), KeReleaseSemaphore(), KernelMode, KeWaitForSingleObject(), KPROCESSOR_MODE, _ETHREAD::LpcExitThreadCalled, LpcpAcquireLpcpLock, LpcpAllocateFromPortZone(), LpcpFreeDataInfoMessage(), LpcpFreeToPortZone(), LpcpMoveMessage(), LpcpPrint, LpcpReferencePortObject, LpcpReleaseLpcpLock, LpcpSaveThread, LpcpTrace, _ETHREAD::LpcReceivedMessageId, _ETHREAD::LpcReceivedMsgIdValid, _ETHREAD::LpcReplyChain, _ETHREAD::LpcReplyMessage, _ETHREAD::LpcReplyMessageId, _ETHREAD::LpcReplySemaphore, _LPCP_PORT_OBJECT::MaxMessageLength, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObject, PAGED_CODE, PortHandle, ProbeForWrite(), PsGetCurrentProcess, PsGetCurrentThread, PsLookupProcessThreadByCid(), ReplyMessage(), _LPCP_MESSAGE::Request, Status, THREAD_TO_PROCESS, TRUE, and WrExecutive.

Referenced by SendRequest().

00382 : 00383 00384 A client and server process can send a reply to a previous message and 00385 block waiting for a reply using the NtReplyWaitReplyPort service: 00386 00387 This service works the same as NtReplyPort, except that after delivering 00388 the reply message, it blocks waiting for a reply to a previous message. 00389 When the reply is received, it will be placed in the location specified 00390 by the ReplyMessage parameter. 00391 00392 Arguments: 00393 00394 PortHandle - Specifies the handle of the communication port that the 00395 original message was received from. 00396 00397 ReplyMessage - Specifies a pointer to the reply message to be sent. 00398 The ClientId and MessageId fields determine which thread will 00399 get the reply. This buffer also receives any reply that comes 00400 back from the wait. 00401 00402 Return Value: 00403 00404 Status code that indicates whether or not the operation was 00405 successful. 00406 00407 --*/ 00408 00409 { 00410 KPROCESSOR_MODE PreviousMode; 00411 NTSTATUS Status; 00412 PLPCP_PORT_OBJECT PortObject; 00413 PORT_MESSAGE CapturedReplyMessage; 00414 PLPCP_MESSAGE Msg; 00415 PETHREAD CurrentThread; 00416 PETHREAD WakeupThread; 00417 00418 PAGED_CODE(); 00419 00420 CurrentThread = PsGetCurrentThread(); 00421 00422 // 00423 // Get previous processor mode and probe output arguments if necessary. 00424 // 00425 00426 PreviousMode = KeGetPreviousMode(); 00427 00428 if (PreviousMode != KernelMode) { 00429 00430 try { 00431 00432 ProbeForWrite( ReplyMessage, 00433 sizeof( *ReplyMessage ), 00434 sizeof( ULONG )); 00435 00436 CapturedReplyMessage = *ReplyMessage; 00437 00438 } except( EXCEPTION_EXECUTE_HANDLER ) { 00439 00440 return GetExceptionCode(); 00441 } 00442 00443 } else { 00444 00445 CapturedReplyMessage = *ReplyMessage; 00446 } 00447 00448 // 00449 // Make sure DataLength is valid with respect to header size and total length 00450 // 00451 00452 if ((((CLONG)CapturedReplyMessage.u1.s1.DataLength) + sizeof( PORT_MESSAGE )) > 00453 ((CLONG)CapturedReplyMessage.u1.s1.TotalLength)) { 00454 00455 return STATUS_INVALID_PARAMETER; 00456 } 00457 00458 // 00459 // Make sure the user didn't give us a bogus reply message id 00460 // 00461 00462 if (CapturedReplyMessage.MessageId == 0) { 00463 00464 return STATUS_INVALID_PARAMETER; 00465 } 00466 00467 // 00468 // Reference the communication port object by handle. Return status if 00469 // unsuccessful. 00470 // 00471 00472 Status = LpcpReferencePortObject( PortHandle, 00473 0, 00474 PreviousMode, 00475 &PortObject ); 00476 00477 if (!NT_SUCCESS( Status )) { 00478 00479 return Status; 00480 } 00481 00482 LpcpSaveThread (PortObject); 00483 00484 // 00485 // Validate the message length 00486 // 00487 00488 if (((ULONG)CapturedReplyMessage.u1.s1.TotalLength > PortObject->MaxMessageLength) || 00489 ((ULONG)CapturedReplyMessage.u1.s1.TotalLength <= (ULONG)CapturedReplyMessage.u1.s1.DataLength)) { 00490 00491 ObDereferenceObject( PortObject ); 00492 00493 return STATUS_PORT_MESSAGE_TOO_LONG; 00494 } 00495 00496 // 00497 // Translate the ClientId from the connection request into a 00498 // thread pointer. This is a referenced pointer to keep the thread 00499 // from evaporating out from under us. 00500 // 00501 00502 Status = PsLookupProcessThreadByCid( &CapturedReplyMessage.ClientId, 00503 NULL, 00504 &WakeupThread ); 00505 00506 if (!NT_SUCCESS( Status )) { 00507 00508 ObDereferenceObject( PortObject ); 00509 00510 return Status; 00511 } 00512 00513 // 00514 // Acquire the mutex that gaurds the LpcReplyMessage field of 00515 // the thread and get the pointer to the message that the thread 00516 // is waiting for a reply to. 00517 // 00518 00519 LpcpAcquireLpcpLock(); 00520 00521 Msg = (PLPCP_MESSAGE)LpcpAllocateFromPortZone( CapturedReplyMessage.u1.s1.TotalLength ); 00522 00523 if (Msg == NULL) { 00524 00525 LpcpReleaseLpcpLock(); 00526 00527 ObDereferenceObject( WakeupThread ); 00528 ObDereferenceObject( PortObject ); 00529 00530 return STATUS_NO_MEMORY; 00531 } 00532 00533 // 00534 // See if the thread is waiting for a reply to the message 00535 // specified on this call. If not then a bogus message 00536 // has been specified, so release the mutex, dereference the thread 00537 // and return failure. 00538 // 00539 // We also fail this request if the caller isn't replying to a request 00540 // message. For example, if the caller is replying to a connection 00541 // request 00542 // 00543 00544 if ((WakeupThread->LpcReplyMessageId != CapturedReplyMessage.MessageId) 00545 00546 || 00547 00548 ((WakeupThread->LpcReplyMessage != NULL) && 00549 (((PLPCP_MESSAGE)(WakeupThread->LpcReplyMessage))->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) != LPC_REQUEST)) { 00550 00551 LpcpPrint(( "%s Attempted reply wait reply to Thread %lx (%s)\n", 00552 PsGetCurrentProcess()->ImageFileName, 00553 WakeupThread, 00554 THREAD_TO_PROCESS( WakeupThread )->ImageFileName )); 00555 00556 LpcpPrint(( "failed. MessageId == %u Client Id: %x.%x\n", 00557 CapturedReplyMessage.MessageId, 00558 CapturedReplyMessage.ClientId.UniqueProcess, 00559 CapturedReplyMessage.ClientId.UniqueThread )); 00560 00561 LpcpPrint(( " Thread MessageId == %u Client Id: %x.%x\n", 00562 WakeupThread->LpcReplyMessageId, 00563 WakeupThread->Cid.UniqueProcess, 00564 WakeupThread->Cid.UniqueThread )); 00565 00566 #if DBG 00567 if (LpcpStopOnReplyMismatch) { 00568 00569 DbgBreakPoint(); 00570 } 00571 #endif 00572 00573 LpcpFreeToPortZone( Msg, TRUE ); 00574 00575 LpcpReleaseLpcpLock(); 00576 00577 ObDereferenceObject( WakeupThread ); 00578 ObDereferenceObject( PortObject ); 00579 00580 return STATUS_REPLY_MESSAGE_MISMATCH; 00581 } 00582 00583 // 00584 // Copy the reply message to the request message buffer. Do this before 00585 // we actually fiddle with the wakeup threads fields. Otherwise we 00586 // could mess up its state 00587 // 00588 00589 try { 00590 00591 LpcpMoveMessage( &Msg->Request, 00592 &CapturedReplyMessage, 00593 (ReplyMessage + 1), 00594 LPC_REPLY, 00595 NULL ); 00596 00597 } except( EXCEPTION_EXECUTE_HANDLER ) { 00598 00599 LpcpFreeToPortZone( Msg, TRUE ); 00600 00601 LpcpReleaseLpcpLock(); 00602 00603 ObDereferenceObject( WakeupThread ); 00604 ObDereferenceObject( PortObject ); 00605 00606 return (Status = GetExceptionCode()); 00607 } 00608 00609 // 00610 // At this point we know the thread is waiting for our reply 00611 // 00612 00613 LpcpTrace(( "%s Sending Reply Wait Reply Msg %lx (%u, %x) [%08x %08x %08x %08x] to Thread %lx (%s)\n", 00614 PsGetCurrentProcess()->ImageFileName, 00615 Msg, 00616 CapturedReplyMessage.MessageId, 00617 CapturedReplyMessage.u2.s2.DataInfoOffset, 00618 *((PULONG)(Msg+1)+0), 00619 *((PULONG)(Msg+1)+1), 00620 *((PULONG)(Msg+1)+2), 00621 *((PULONG)(Msg+1)+3), 00622 WakeupThread, 00623 THREAD_TO_PROCESS( WakeupThread )->ImageFileName )); 00624 00625 // 00626 // Locate and free the messsage from the port. This call use to 00627 // test for (CapturedReplyMessage.u2.s2.DataInfoOffset != 0) as a 00628 // prerequisite for doing the call. 00629 // 00630 00631 LpcpFreeDataInfoMessage( PortObject, 00632 CapturedReplyMessage.MessageId, 00633 CapturedReplyMessage.CallbackId ); 00634 00635 // 00636 // Add an extra reference so LpcExitThread does not evaporate 00637 // the pointer before we get to the wait below 00638 // 00639 00640 ObReferenceObject( WakeupThread ); 00641 00642 // 00643 // Release the mutex that guards the LpcReplyMessage field 00644 // after marking message as being replied to. 00645 // 00646 00647 Msg->RepliedToThread = WakeupThread; 00648 00649 WakeupThread->LpcReplyMessageId = 0; 00650 WakeupThread->LpcReplyMessage = (PVOID)Msg; 00651 00652 // 00653 // Remove the thread from the reply rundown list as we are sending the reply. 00654 // 00655 00656 if (!WakeupThread->LpcExitThreadCalled && !IsListEmpty( &WakeupThread->LpcReplyChain )) { 00657 00658 RemoveEntryList( &WakeupThread->LpcReplyChain ); 00659 00660 InitializeListHead( &WakeupThread->LpcReplyChain ); 00661 } 00662 00663 // 00664 // Set ourselves up to get the following reply 00665 // 00666 00667 CurrentThread->LpcReplyMessageId = CapturedReplyMessage.MessageId; 00668 CurrentThread->LpcReplyMessage = NULL; 00669 00670 if ((CurrentThread->LpcReceivedMsgIdValid) && 00671 (CurrentThread->LpcReceivedMessageId == CapturedReplyMessage.MessageId)) { 00672 00673 CurrentThread->LpcReceivedMessageId = 0; 00674 CurrentThread->LpcReceivedMsgIdValid = FALSE; 00675 } 00676 00677 LpcpReleaseLpcpLock(); 00678 00679 // 00680 // Wake up the thread that is waiting for an answer to its request 00681 // inside of NtRequestWaitReplyPort or NtReplyWaitReplyPort. That 00682 // will dereference itself when it wakes up. 00683 // 00684 00685 KeReleaseSemaphore( &WakeupThread->LpcReplySemaphore, 00686 1, 00687 1, 00688 FALSE ); 00689 00690 ObDereferenceObject( WakeupThread ); 00691 00692 // 00693 // And wait for a reply 00694 // 00695 00696 Status = KeWaitForSingleObject( &CurrentThread->LpcReplySemaphore, 00697 Executive, 00698 PreviousMode, 00699 FALSE, 00700 NULL ); 00701 00702 if (Status == STATUS_USER_APC) { 00703 00704 // 00705 // if the semaphore is signaled, then clear it 00706 // 00707 00708 if (KeReadStateSemaphore( &CurrentThread->LpcReplySemaphore )) { 00709 00710 KeWaitForSingleObject( &CurrentThread->LpcReplySemaphore, 00711 WrExecutive, 00712 KernelMode, 00713 FALSE, 00714 NULL ); 00715 00716 Status = STATUS_SUCCESS; 00717 } 00718 } 00719 00720 // 00721 // If the wait succeeded, copy the reply to the reply buffer. 00722 // 00723 00724 if (Status == STATUS_SUCCESS) { 00725 00726 // 00727 // Acquire the mutex that guards the request message queue. Remove 00728 // the request message from the list of messages being processed and 00729 // free the message back to the queue's zone. If the zone's free 00730 // list was zero before freeing this message then pulse the free 00731 // event after free the message so that threads waiting to allocate 00732 // a request message buffer will wake up. Finally, release the mutex 00733 // and return the system service status. 00734 // 00735 00736 LpcpAcquireLpcpLock(); 00737 00738 Msg = CurrentThread->LpcReplyMessage; 00739 CurrentThread->LpcReplyMessage = NULL; 00740 00741 #if DBG 00742 if (Msg != NULL) { 00743 00744 LpcpTrace(( "%s Got Reply Msg %lx (%u) [%08x %08x %08x %08x] for Thread %lx (%s)\n", 00745 PsGetCurrentProcess()->ImageFileName, 00746 Msg, 00747 Msg->Request.MessageId, 00748 *((PULONG)(Msg+1)+0), 00749 *((PULONG)(Msg+1)+1), 00750 *((PULONG)(Msg+1)+2), 00751 *((PULONG)(Msg+1)+3), 00752 CurrentThread, 00753 THREAD_TO_PROCESS( CurrentThread )->ImageFileName )); 00754 00755 if (!IsListEmpty( &Msg->Entry )) { 00756 00757 LpcpTrace(( "Reply Msg %lx has non-empty list entry\n", Msg )); 00758 } 00759 } 00760 #endif 00761 00762 LpcpReleaseLpcpLock(); 00763 00764 if (Msg != NULL) { 00765 00766 try { 00767 00768 LpcpMoveMessage( ReplyMessage, 00769 &Msg->Request, 00770 (&Msg->Request) + 1, 00771 0, 00772 NULL ); 00773 00774 } except( EXCEPTION_EXECUTE_HANDLER ) { 00775 00776 Status = GetExceptionCode(); 00777 } 00778 00779 // 00780 // Acquire the LPC mutex and decrement the reference count for the 00781 // message. If the reference count goes to zero the message will be 00782 // deleted. 00783 // 00784 00785 LpcpAcquireLpcpLock(); 00786 00787 if (Msg->RepliedToThread != NULL) { 00788 00789 ObDereferenceObject( Msg->RepliedToThread ); 00790 00791 Msg->RepliedToThread = NULL; 00792 } 00793 00794 LpcpFreeToPortZone( Msg, TRUE ); 00795 00796 LpcpReleaseLpcpLock(); 00797 } 00798 } 00799 00800 ObDereferenceObject( PortObject ); 00801 00802 return Status; 00803 }

NTSTATUS NtWriteRequestData IN HANDLE  PortHandle,
IN PPORT_MESSAGE  Message,
IN ULONG  DataEntryIndex,
IN PVOID  Buffer,
IN ULONG  BufferSize,
OUT PULONG NumberOfBytesWritten  OPTIONAL
 

Definition at line 859 of file lpcreply.c.

References Buffer, BufferSize, LpcpCopyRequestData(), PAGED_CODE, PortHandle, and TRUE.

00870 : 00871 00872 This routine is used to copy data from the user supplied buffer into the 00873 port message 00874 00875 Arguments: 00876 00877 PortHandle - Supplies the port into which the message is being written 00878 00879 Message - Supplies the message that we are trying to write 00880 00881 DataEntryIndex - Supplies the index of the port data entry in the 00882 preceeding message that we are writing 00883 00884 Buffer - Supplies the location into which the data is to be written 00885 00886 BufferSize - Supplies the size, in bytes, of the preceeding buffer 00887 00888 NumberOfBytesRead - Optionally returns the number of bytes written from 00889 the buffer 00890 00891 Return Value: 00892 00893 NTSTATUS - An appropriate status value 00894 00895 --*/ 00896 00897 { 00898 PAGED_CODE(); 00899 00900 return LpcpCopyRequestData( TRUE, 00901 PortHandle, 00902 Message, 00903 DataEntryIndex, 00904 Buffer, 00905 BufferSize, 00906 NumberOfBytesWritten ); 00907 }


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