686 lines
22 KiB
C
686 lines
22 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1999 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
rndis.c
|
||
|
|
||
|
|
||
|
Author:
|
||
|
|
||
|
ervinp
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
Kernel mode
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
|
||
|
--*/
|
||
|
|
||
|
|
||
|
#include <ndis.h>
|
||
|
#include <ntddndis.h> // defines OID's
|
||
|
|
||
|
#include "..\inc\rndis.h"
|
||
|
#include "..\inc\rndisapi.h"
|
||
|
|
||
|
#include "usb8023.h"
|
||
|
#include "debug.h"
|
||
|
|
||
|
|
||
|
|
||
|
NDIS_STATUS RndisInitializeHandler( OUT PNDIS_HANDLE pMiniportAdapterContext,
|
||
|
OUT PULONG pMaxReceiveSize,
|
||
|
IN NDIS_HANDLE RndisMiniportHandle,
|
||
|
IN NDIS_HANDLE NdisMiniportHandle,
|
||
|
IN NDIS_HANDLE WrapperConfigurationContext,
|
||
|
IN PDEVICE_OBJECT Pdo)
|
||
|
{
|
||
|
NDIS_STATUS rndisStat;
|
||
|
ADAPTEREXT *adapter;
|
||
|
|
||
|
DBGVERBOSE(("RndisInitializeHandler"));
|
||
|
|
||
|
/*
|
||
|
* Allocate a new device object to represent this connection.
|
||
|
*/
|
||
|
adapter = NewAdapter(Pdo);
|
||
|
if (adapter){
|
||
|
|
||
|
adapter->ndisAdapterHandle = (PVOID)NdisMiniportHandle;
|
||
|
adapter->rndisAdapterHandle = (PVOID)RndisMiniportHandle;
|
||
|
|
||
|
|
||
|
if (InitUSB(adapter)){
|
||
|
|
||
|
/*
|
||
|
* Figure out the buffer size required for each packet.
|
||
|
*
|
||
|
* For native RNDIS, the buffer must include the rndis message and RNDIS_PACKET.
|
||
|
* For KLSI, we have to prepend a two-byte size field to each packet.
|
||
|
* For other prototypes, we have to append zeroes to round the length
|
||
|
* up to the next multiple of the endpoint packet size.
|
||
|
*
|
||
|
* We must also need one extra byte for the one-byte short packet that
|
||
|
* must follow a full-sized frame.
|
||
|
*/
|
||
|
ASSERT(adapter->writePipeLength);
|
||
|
ASSERT(adapter->readPipeLength);
|
||
|
|
||
|
/*
|
||
|
* Allocate common resources before miniport-specific resources
|
||
|
* because we need to allocate the packet pool first.
|
||
|
*/
|
||
|
if (AllocateCommonResources(adapter)){
|
||
|
|
||
|
EnqueueAdapter(adapter);
|
||
|
|
||
|
/*
|
||
|
* Give RNDIS our adapter context, which it will use to call us.
|
||
|
*/
|
||
|
*pMiniportAdapterContext = (NDIS_HANDLE)adapter;
|
||
|
|
||
|
*pMaxReceiveSize = PACKET_BUFFER_SIZE;
|
||
|
|
||
|
rndisStat = NDIS_STATUS_SUCCESS;
|
||
|
}
|
||
|
else {
|
||
|
rndisStat = NDIS_STATUS_NOT_ACCEPTED;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
rndisStat = NDIS_STATUS_NOT_ACCEPTED;
|
||
|
}
|
||
|
|
||
|
if (rndisStat != NDIS_STATUS_SUCCESS){
|
||
|
FreeAdapter(adapter);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
rndisStat = NDIS_STATUS_NOT_ACCEPTED;
|
||
|
}
|
||
|
|
||
|
return rndisStat;
|
||
|
}
|
||
|
|
||
|
|
||
|
NDIS_STATUS RndisInitCompleteNotify(IN NDIS_HANDLE MicroportAdapterContext,
|
||
|
IN ULONG DeviceFlags,
|
||
|
IN OUT PULONG pMaxTransferSize)
|
||
|
{
|
||
|
ADAPTEREXT *adapter = (ADAPTEREXT *)MicroportAdapterContext;
|
||
|
|
||
|
if (*pMaxTransferSize > PACKET_BUFFER_SIZE) {
|
||
|
|
||
|
DBGWARN(("Reducing adapter MaxTransferSize from %xh to %xh.",
|
||
|
*pMaxTransferSize, PACKET_BUFFER_SIZE));
|
||
|
|
||
|
*pMaxTransferSize = PACKET_BUFFER_SIZE;
|
||
|
}
|
||
|
|
||
|
StartUSBReadLoop(adapter);
|
||
|
|
||
|
return NDIS_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID RndisHalt(IN NDIS_HANDLE MicroportAdapterContext)
|
||
|
{
|
||
|
BOOLEAN workItemOrTimerPending;
|
||
|
KIRQL oldIrql;
|
||
|
ADAPTEREXT *adapter = (ADAPTEREXT *)MicroportAdapterContext;
|
||
|
|
||
|
ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
|
||
|
|
||
|
DBGOUT(("> RndisHalt(%ph)", adapter));
|
||
|
|
||
|
ASSERT(adapter->sig == DRIVER_SIG);
|
||
|
|
||
|
HaltAdapter(adapter);
|
||
|
|
||
|
KeAcquireSpinLock(&adapter->adapterSpinLock, &oldIrql);
|
||
|
workItemOrTimerPending = adapter->workItemOrTimerPending;
|
||
|
KeReleaseSpinLock(&adapter->adapterSpinLock, oldIrql);
|
||
|
|
||
|
if (workItemOrTimerPending){
|
||
|
/*
|
||
|
* Wait until workItem fires back to us before freeing the adapter context.
|
||
|
*/
|
||
|
KeWaitForSingleObject(&adapter->workItemOrTimerEvent, Executive, KernelMode, FALSE, NULL);
|
||
|
}
|
||
|
|
||
|
DequeueAdapter(adapter);
|
||
|
|
||
|
FreeAdapter(adapter);
|
||
|
|
||
|
#if DBG_WRAP_MEMORY
|
||
|
if (dbgTotalMemCount != 0){
|
||
|
DBGERR(("RndisHalt: unloading with %xh bytes still allocated !!", dbgTotalMemCount));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
DBGOUT(("< RndisHalt"));
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID RndisShutdown(IN NDIS_HANDLE MicroportAdapterContext)
|
||
|
{
|
||
|
ADAPTEREXT *adapter = (ADAPTEREXT *)MicroportAdapterContext;
|
||
|
|
||
|
DBGOUT(("RndisShutdown(%ph)", adapter));
|
||
|
|
||
|
#if DBG_WRAP_MEMORY
|
||
|
if (dbgTotalMemCount != 0){
|
||
|
DBGERR(("RndisShutdown: unloading with %xh bytes still allocated !!", dbgTotalMemCount));
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID RndisSendMessageHandler( IN NDIS_HANDLE MicroportAdapterContext,
|
||
|
IN PMDL pMessageMdl,
|
||
|
IN NDIS_HANDLE RndisMessageHandle,
|
||
|
IN RM_CHANNEL_TYPE ChannelType)
|
||
|
{
|
||
|
ADAPTEREXT *adapter = (ADAPTEREXT *)MicroportAdapterContext;
|
||
|
|
||
|
ASSERT(adapter->sig == DRIVER_SIG);
|
||
|
|
||
|
if (!adapter->resetting){
|
||
|
/*
|
||
|
* The message header is guaranteed to be contained in the first buffer of the MDL.
|
||
|
*/
|
||
|
PRNDIS_MESSAGE pMsg = GetSystemAddressForMdlSafe(pMessageMdl);
|
||
|
if (pMsg){
|
||
|
|
||
|
ASSERT(!adapter->halting);
|
||
|
|
||
|
if (adapter->numActiveWritePackets <= USB_PACKET_POOL_SIZE*3/4){
|
||
|
|
||
|
USBPACKET *packet = DequeueFreePacket(adapter);
|
||
|
if (packet){
|
||
|
|
||
|
packet->rndisMessageHandle = (PVOID)RndisMessageHandle;
|
||
|
|
||
|
/*
|
||
|
* Move our packet to the usbPendingWritePackets queue
|
||
|
* and send it down the USB pipe.
|
||
|
* Native RNDIS packet messages go intact to the write pipe.
|
||
|
* All other encapsulated commands go to the control pipe.
|
||
|
*/
|
||
|
EnqueuePendingWritePacket(packet);
|
||
|
|
||
|
if (ChannelType == RMC_DATA) {
|
||
|
ASSERT(!packet->ndisSendPktMdl);
|
||
|
|
||
|
#ifdef RAW_TEST
|
||
|
if (adapter->rawTest) {
|
||
|
pMessageMdl = AddDataHeader(pMessageMdl);
|
||
|
if (pMessageMdl == NULL) {
|
||
|
DequeuePendingWritePacket(packet);
|
||
|
RndisMSendComplete( (NDIS_HANDLE)adapter->rndisAdapterHandle,
|
||
|
RndisMessageHandle,
|
||
|
NDIS_STATUS_RESOURCES);
|
||
|
return;
|
||
|
}
|
||
|
packet->dataPacket = TRUE;
|
||
|
}
|
||
|
#endif // RAW_TEST
|
||
|
|
||
|
packet->ndisSendPktMdl = pMessageMdl;
|
||
|
packet->dataBufferCurrentLength = CopyMdlToBuffer(packet->dataBuffer, pMessageMdl, packet->dataBufferMaxLength);
|
||
|
|
||
|
SubmitUSBWritePacket(packet);
|
||
|
}
|
||
|
else {
|
||
|
NTSTATUS status;
|
||
|
ULONG msgType = pMsg->NdisMessageType;
|
||
|
BOOLEAN synchronizeUSBcall = FALSE;
|
||
|
ULONG oid;
|
||
|
RNDIS_REQUEST_ID reqId;
|
||
|
|
||
|
switch (msgType){
|
||
|
|
||
|
case REMOTE_NDIS_INITIALIZE_MSG:
|
||
|
{
|
||
|
ULONG maxXferSize = pMsg->Message.InitializeRequest.MaxTransferSize;
|
||
|
DBGOUT(("---- REMOTE_NDIS_INITIALIZE_MSG (MaxTransferSize = %xh) ----", maxXferSize));
|
||
|
ASSERT(maxXferSize <= PACKET_BUFFER_SIZE);
|
||
|
adapter->rndismpMajorVersion = pMsg->Message.InitializeRequest.MajorVersion;
|
||
|
adapter->rndismpMinorVersion = pMsg->Message.InitializeRequest.MinorVersion;
|
||
|
adapter->rndismpMaxTransferSize = maxXferSize;
|
||
|
synchronizeUSBcall = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case REMOTE_NDIS_SET_MSG:
|
||
|
case REMOTE_NDIS_QUERY_MSG:
|
||
|
oid = pMsg->Message.SetRequest.Oid;
|
||
|
reqId = pMsg->Message.SetRequest.RequestId;
|
||
|
|
||
|
DBGVERBOSE(("> %s (req#%d)", DbgGetOidName(oid), reqId));
|
||
|
|
||
|
if (oid == OID_GEN_CURRENT_PACKET_FILTER){
|
||
|
ULONG pktFilter = *(PULONG)((PUCHAR)&pMsg->Message.SetRequest+pMsg->Message.SetRequest.InformationBufferOffset);
|
||
|
adapter->currentPacketFilter = pktFilter;
|
||
|
adapter->gotPacketFilterIndication = TRUE;
|
||
|
DBGOUT(("---- Got OID_GEN_CURRENT_PACKET_FILTER (%xh) ----", pktFilter));
|
||
|
}
|
||
|
else if (oid == OID_802_3_CURRENT_ADDRESS){
|
||
|
/*
|
||
|
* This oid can be a query or a set.
|
||
|
* If it's a set, save the assigned
|
||
|
* MAC address in case we need to simulate
|
||
|
* it later on a reset.
|
||
|
*/
|
||
|
if (msgType == REMOTE_NDIS_SET_MSG){
|
||
|
ASSERT(pMsg->Message.SetRequest.InformationBufferLength == ETHERNET_ADDRESS_LENGTH);
|
||
|
DBGVERBOSE(("COVERAGE - OID_802_3_CURRENT_ADDRESS (SET), msg=%xh.", pMsg));
|
||
|
RtlMoveMemory( adapter->MAC_Address,
|
||
|
((PUCHAR)&pMsg->Message.SetRequest+pMsg->Message.SetRequest.InformationBufferOffset),
|
||
|
ETHERNET_ADDRESS_LENGTH);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
adapter->dbgCurrentOid = oid;
|
||
|
|
||
|
break;
|
||
|
|
||
|
case REMOTE_NDIS_RESET_MSG:
|
||
|
DBGWARN(("---- REMOTE_NDIS_RESET_MSG ----"));
|
||
|
adapter->numSoftResets++;
|
||
|
break;
|
||
|
|
||
|
case REMOTE_NDIS_HALT_MSG:
|
||
|
DBGWARN(("---- REMOTE_NDIS_HALT_MSG ----"));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
packet->dataBufferCurrentLength = CopyMdlToBuffer( packet->dataBuffer,
|
||
|
pMessageMdl,
|
||
|
packet->dataBufferMaxLength);
|
||
|
|
||
|
#ifdef RAW_TEST
|
||
|
packet->dataPacket = FALSE;
|
||
|
#endif
|
||
|
status = SubmitPacketToControlPipe(packet, synchronizeUSBcall, FALSE);
|
||
|
|
||
|
/*
|
||
|
* If this is an init message, then start reading the notify pipe.
|
||
|
*/
|
||
|
switch (msgType){
|
||
|
|
||
|
case REMOTE_NDIS_INITIALIZE_MSG:
|
||
|
if (NT_SUCCESS(status)){
|
||
|
adapter->initialized = TRUE;
|
||
|
SubmitNotificationRead(adapter, FALSE);
|
||
|
}
|
||
|
else {
|
||
|
DBGERR(("Device failed REMOTE_NDIS_INITIALIZE_MSG with %xh.", status));
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
RndisMSendComplete( (NDIS_HANDLE)adapter->rndisAdapterHandle,
|
||
|
RndisMessageHandle,
|
||
|
NDIS_STATUS_RESOURCES);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
DBGWARN(("RndisSendMessageHandler: throttling sends because only %d packets available for rcv ", USB_PACKET_POOL_SIZE-adapter->numActiveWritePackets));
|
||
|
RndisMSendComplete( (NDIS_HANDLE)adapter->rndisAdapterHandle,
|
||
|
RndisMessageHandle,
|
||
|
NDIS_STATUS_RESOURCES);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
DBGERR(("GetSystemAddressForMdlSafe failed"));
|
||
|
RndisMSendComplete( (NDIS_HANDLE)adapter->rndisAdapterHandle,
|
||
|
RndisMessageHandle,
|
||
|
NDIS_STATUS_INVALID_PACKET);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
DBGWARN(("RndisSendMessageHandler - failing send because adapter is resetting"));
|
||
|
RndisMSendComplete( (NDIS_HANDLE)adapter->rndisAdapterHandle,
|
||
|
RndisMessageHandle,
|
||
|
NDIS_STATUS_MEDIA_BUSY);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* RndisReturnMessageHandler
|
||
|
*
|
||
|
* This is the completion of a received packet indication call.
|
||
|
*/
|
||
|
VOID RndisReturnMessageHandler( IN NDIS_HANDLE MicroportAdapterContext,
|
||
|
IN PMDL pMessageMdl,
|
||
|
IN NDIS_HANDLE MicroportMessageContext)
|
||
|
{
|
||
|
USBPACKET *packet;
|
||
|
|
||
|
DBGVERBOSE(("RndisReturnMessageHandler: msgMdl=%ph, msg context = %ph.", pMessageMdl, MicroportMessageContext));
|
||
|
|
||
|
ASSERT(MicroportMessageContext);
|
||
|
packet = (USBPACKET *)MicroportMessageContext;
|
||
|
ASSERT(packet->sig == DRIVER_SIG);
|
||
|
|
||
|
#ifdef RAW_TEST
|
||
|
{
|
||
|
ADAPTEREXT * adapter = (ADAPTEREXT *)MicroportAdapterContext;
|
||
|
if (adapter->rawTest) {
|
||
|
if (packet->dataPacket) {
|
||
|
UnskipRcvRndisPacketHeader(packet);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif // RAW_TEST
|
||
|
|
||
|
/*
|
||
|
* The receive indication is done.
|
||
|
* Put our packet back in the free list.
|
||
|
*/
|
||
|
DequeueCompletedReadPacket(packet);
|
||
|
EnqueueFreePacket(packet);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOLEAN RegisterRNDISMicroport(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
|
||
|
{
|
||
|
RNDIS_MICROPORT_CHARACTERISTICS rndisAttribs;
|
||
|
NDIS_HANDLE ndisWrapperHandle;
|
||
|
|
||
|
DBGVERBOSE(("RegisterRNDISMicroport"));
|
||
|
|
||
|
RtlZeroMemory(&rndisAttribs, sizeof(rndisAttribs));
|
||
|
rndisAttribs.RndisVersion = RNDIS_VERSION;
|
||
|
rndisAttribs.Reserved = 0;
|
||
|
rndisAttribs.RmInitializeHandler = RndisInitializeHandler;
|
||
|
rndisAttribs.RmInitCompleteNotifyHandler = RndisInitCompleteNotify;
|
||
|
rndisAttribs.RmHaltHandler = RndisHalt;
|
||
|
rndisAttribs.RmShutdownHandler = RndisShutdown;
|
||
|
rndisAttribs.RmSendMessageHandler = RndisSendMessageHandler;
|
||
|
rndisAttribs.RmReturnMessageHandler = RndisReturnMessageHandler;
|
||
|
|
||
|
RndisMInitializeWrapper( &ndisWrapperHandle,
|
||
|
NULL,
|
||
|
DriverObject,
|
||
|
RegistryPath,
|
||
|
&rndisAttribs);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
VOID IndicateSendStatusToRNdis(USBPACKET *packet, NTSTATUS status)
|
||
|
{
|
||
|
#ifdef RAW_TEST
|
||
|
ADAPTEREXT *adapter = packet->adapter;
|
||
|
|
||
|
if (adapter->rawTest && packet->dataPacket) {
|
||
|
FreeDataHeader(packet);
|
||
|
}
|
||
|
#endif /? RAW_TEST
|
||
|
|
||
|
packet->ndisSendPktMdl = NULL;
|
||
|
|
||
|
ASSERT(packet->rndisMessageHandle);
|
||
|
|
||
|
RndisMSendComplete( (NDIS_HANDLE)packet->adapter->rndisAdapterHandle,
|
||
|
(NDIS_HANDLE)packet->rndisMessageHandle,
|
||
|
(NDIS_STATUS)status);
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID RNDISProcessNotification(ADAPTEREXT *adapter)
|
||
|
{
|
||
|
UCHAR notification = *(PUCHAR)adapter->notifyBuffer;
|
||
|
UCHAR notificationCode = *((PUCHAR)adapter->notifyBuffer + 1);
|
||
|
|
||
|
if ((notification == NATIVE_RNDIS_RESPONSE_AVAILABLE) ||
|
||
|
((notification == CDC_RNDIS_NOTIFICATION) &&
|
||
|
(notificationCode == CDC_RNDIS_RESPONSE_AVAILABLE)))
|
||
|
{
|
||
|
/*
|
||
|
* Try to read a native RNDIS encapsulated command from the control pipe.
|
||
|
*/
|
||
|
DBGVERBOSE(("NativeRNDISProcessNotification: NATIVE_RNDIS_RESPONSE_AVAILABLE"));
|
||
|
{
|
||
|
USBPACKET *packet = DequeueFreePacket(adapter);
|
||
|
if (packet){
|
||
|
EnqueuePendingReadPacket(packet);
|
||
|
ReadPacketFromControlPipe(packet, FALSE);
|
||
|
}
|
||
|
else {
|
||
|
DBGWARN(("couldn't get free packet in NativeRNDISProcessNotification"));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
DBGERR(("NativeRNDISProcessNotification: unknown notification %xh.", notification));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
NTSTATUS IndicateRndisMessage( IN USBPACKET *packet,
|
||
|
IN BOOLEAN bIsData)
|
||
|
{
|
||
|
ADAPTEREXT *adapter = packet->adapter;
|
||
|
PRNDIS_MESSAGE rndisMsg = (PRNDIS_MESSAGE)packet->dataBuffer;
|
||
|
NDIS_STATUS rcvStat;
|
||
|
|
||
|
ASSERT(packet->dataBufferCurrentLength <= packet->dataBufferMaxLength);
|
||
|
|
||
|
/*
|
||
|
* Indicate the packet to RNDIS, and pass a pointer to our usb packet
|
||
|
* as the MicroportMessageContext.
|
||
|
* The packet/message will be returned to us via RndisReturnMessageHandler.
|
||
|
*/
|
||
|
MyInitializeMdl(packet->dataBufferMdl, packet->dataBuffer, packet->dataBufferCurrentLength);
|
||
|
if (adapter->numFreePackets < USB_PACKET_POOL_SIZE/8){
|
||
|
rcvStat = NDIS_STATUS_RESOURCES;
|
||
|
}
|
||
|
else {
|
||
|
rcvStat = NDIS_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
#ifdef RAW_TEST
|
||
|
if (adapter->rawTest) {
|
||
|
packet->dataPacket = bIsData;
|
||
|
if (bIsData) {
|
||
|
SkipRcvRndisPacketHeader(packet);
|
||
|
}
|
||
|
}
|
||
|
#endif // RAW_TEST
|
||
|
|
||
|
RndisMIndicateReceive( (NDIS_HANDLE)packet->adapter->rndisAdapterHandle,
|
||
|
packet->dataBufferMdl,
|
||
|
(NDIS_HANDLE)packet,
|
||
|
(bIsData? RMC_DATA: RMC_CONTROL),
|
||
|
rcvStat);
|
||
|
|
||
|
return STATUS_PENDING;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef RAW_TEST
|
||
|
|
||
|
//
|
||
|
// Add an RNDIS_PACKET header to a sent "raw" encapsulated Ethernet frame.
|
||
|
//
|
||
|
PMDL AddDataHeader(IN PMDL pMessageMdl)
|
||
|
{
|
||
|
PMDL pHeaderMdl, pTmpMdl;
|
||
|
PRNDIS_MESSAGE pRndisMessage;
|
||
|
PRNDIS_PACKET pRndisPacket;
|
||
|
ULONG TotalLength;
|
||
|
|
||
|
//
|
||
|
// Compute the total length.
|
||
|
//
|
||
|
TotalLength = 0;
|
||
|
for (pTmpMdl = pMessageMdl; pTmpMdl != NULL; pTmpMdl = pTmpMdl->Next)
|
||
|
{
|
||
|
TotalLength += MmGetMdlByteCount(pTmpMdl);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Allocate an RNDIS packet header:
|
||
|
//
|
||
|
pRndisMessage = AllocPool(RNDIS_MESSAGE_SIZE(RNDIS_PACKET));
|
||
|
if (pRndisMessage != NULL) {
|
||
|
|
||
|
pHeaderMdl = IoAllocateMdl(pRndisMessage,
|
||
|
RNDIS_MESSAGE_SIZE(RNDIS_PACKET),
|
||
|
FALSE,
|
||
|
FALSE,
|
||
|
NULL);
|
||
|
|
||
|
if (pHeaderMdl != NULL) {
|
||
|
MmBuildMdlForNonPagedPool(pHeaderMdl);
|
||
|
|
||
|
//
|
||
|
// Fill in the RNDIS message generic header:
|
||
|
//
|
||
|
pRndisMessage->NdisMessageType = REMOTE_NDIS_PACKET_MSG;
|
||
|
pRndisMessage->MessageLength = RNDIS_MESSAGE_SIZE(RNDIS_PACKET) + TotalLength;
|
||
|
|
||
|
//
|
||
|
// Fill in the RNDIS_PACKET structure:
|
||
|
//
|
||
|
pRndisPacket = (PRNDIS_PACKET)&pRndisMessage->Message;
|
||
|
pRndisPacket->DataOffset = sizeof(RNDIS_PACKET);
|
||
|
pRndisPacket->DataLength = TotalLength;
|
||
|
pRndisPacket->OOBDataOffset = 0;
|
||
|
pRndisPacket->OOBDataLength = 0;
|
||
|
pRndisPacket->NumOOBDataElements = 0;
|
||
|
pRndisPacket->PerPacketInfoOffset = 0;
|
||
|
pRndisPacket->PerPacketInfoLength = 0;
|
||
|
pRndisPacket->VcHandle = 0;
|
||
|
pRndisPacket->Reserved = 0;
|
||
|
|
||
|
//
|
||
|
// Link it to the raw data frame:
|
||
|
//
|
||
|
pHeaderMdl->Next = pMessageMdl;
|
||
|
}
|
||
|
else {
|
||
|
FreePool(pRndisMessage);
|
||
|
pHeaderMdl = NULL;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
pHeaderMdl = NULL;
|
||
|
}
|
||
|
|
||
|
return (pHeaderMdl);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Remove an RNDIS_PACKET header that we had added to a raw encapsulated
|
||
|
// Ethernet frame.
|
||
|
//
|
||
|
VOID FreeDataHeader(IN USBPACKET * packet)
|
||
|
{
|
||
|
PMDL pHeaderMdl;
|
||
|
PRNDIS_MESSAGE pRndisMessage;
|
||
|
|
||
|
ASSERT(packet->dataPacket == TRUE);
|
||
|
|
||
|
//
|
||
|
// Take out the MDL we had pre-pended
|
||
|
//
|
||
|
pHeaderMdl = packet->ndisSendPktMdl;
|
||
|
packet->ndisSendPktMdl = pHeaderMdl->Next;
|
||
|
|
||
|
//
|
||
|
// Free the RNDIS_PACKET header:
|
||
|
//
|
||
|
pRndisMessage = MmGetMdlVirtualAddress(pHeaderMdl);
|
||
|
FreePool(pRndisMessage);
|
||
|
|
||
|
//
|
||
|
// ... and the MDL itself.
|
||
|
//
|
||
|
IoFreeMdl(pHeaderMdl);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Modify a received message to skip the RNDIS_PACKET header
|
||
|
// before indicating this up to RNDISMP, to test raw encapsulation.
|
||
|
//
|
||
|
VOID SkipRcvRndisPacketHeader(IN USBPACKET * packet)
|
||
|
{
|
||
|
PMDL pHeaderMdl;
|
||
|
RNDIS_MESSAGE UNALIGNED * pRndisMessage;
|
||
|
RNDIS_PACKET UNALIGNED * pRndisPacket;
|
||
|
ULONG DataLength;
|
||
|
ULONG DataOffset;
|
||
|
|
||
|
//
|
||
|
// Get some info from the received RNDIS_PACKET message.
|
||
|
// Note that this may contain multiple data packets, in which
|
||
|
// case we only pass up the first one.
|
||
|
//
|
||
|
pHeaderMdl = packet->dataBufferMdl;
|
||
|
pRndisMessage = MmGetMdlVirtualAddress(pHeaderMdl);
|
||
|
pRndisPacket = (RNDIS_PACKET UNALIGNED *)&pRndisMessage->Message;
|
||
|
DataLength = pRndisPacket->DataLength;
|
||
|
DataOffset = FIELD_OFFSET(RNDIS_MESSAGE, Message) + pRndisPacket->DataOffset;
|
||
|
|
||
|
//
|
||
|
// Save away some existing values to restore later.
|
||
|
//
|
||
|
packet->rcvDataOffset = DataOffset;
|
||
|
packet->rcvByteCount = pHeaderMdl->ByteCount;
|
||
|
|
||
|
|
||
|
//
|
||
|
// This is ONLY for test purposes. Simply modify the MDL to reflect
|
||
|
// a single "raw" encapsulated frame.
|
||
|
//
|
||
|
pHeaderMdl->ByteOffset += DataOffset;
|
||
|
(ULONG_PTR)pHeaderMdl->MappedSystemVa += DataOffset;
|
||
|
pHeaderMdl->ByteCount = DataLength;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Undo for the above function.
|
||
|
//
|
||
|
VOID UnskipRcvRndisPacketHeader(IN USBPACKET * packet)
|
||
|
{
|
||
|
PMDL pHeaderMdl;
|
||
|
|
||
|
ASSERT(packet->dataPacket == TRUE);
|
||
|
|
||
|
//
|
||
|
// Undo everything we did in the SkipRcv... function.
|
||
|
//
|
||
|
pHeaderMdl = packet->dataBufferMdl;
|
||
|
|
||
|
pHeaderMdl->ByteOffset -= packet->rcvDataOffset;
|
||
|
(ULONG_PTR)pHeaderMdl->MappedSystemVa -= packet->rcvDataOffset;
|
||
|
pHeaderMdl->ByteCount = packet->rcvByteCount;
|
||
|
|
||
|
}
|
||
|
|
||
|
#endif // RAW_TEST
|
||
|
|
||
|
|