"Гром. Как писать драйвера (fb2) " - читать интересную книгу автора

Группа минипорт.

Функции этой группы занимаются обработкой потока данных и событий, происходящих в верхнем уровне драйвера, и вызываемых обращением к NDIS TCP/IP стека.

Если посмотреть на схемы из второй части, то видно, что в нижней части находятся функции протокола, а в верхней минипорта. Почему? Каждый драйвер выступает в двух ипостасях. Общаясь с верхним уровнем драйверов он становиться для него драйвером минипорта, а для нижнего уровня, драйвером протокола.

Список функций минипорт:

MPInitialize – инициализация группы.

MPSend

MPSendPackets

MPTransferData

MPReturnPacket

Функции отвечающие за пересылку пакетов данных.

MPQueryInformation

MPSetInformation

MPQueryPNPCapbilities

MPIsSendOID

MPProcessSetPowerOid

Функции работы с питанием состоянием системы и системой PlagNPlay. Сказать особенно нечего. Стандартное отслеживание внутренних событий системы прописанное Microsoft.

MPHalt – отработка выгрузки и де регистрации драйвера при аварийном.

MPReset – как написано у Microsoft – мы не должны ничего делать :)

Работа с системой – необходимость отрабатывать события важные для сервиса корректно.

MPSetMiniportSecondary

MPPromoteSecondary

MPBundleSearchAndSetSecondary

В системе может быть не один адаптер и соответственно не один драйвер к которому приходится обращаться. В случае такого используются эти функции.

В нашем случае основными функциями из этой группы – являются функции пересылки данных. Все остальные мы можем не рассматривать, их назначение – обслуживать правильно системные связи, вся основная часть которых написана Microsoft.

MPSend

Основная функция вызываемая всегда, при прохождении данных. По правилам работы с данными в NDIS необходимо написать (что в примере и сделано) re-wrap пакету.

Для этого сначала пакет надо захватить, перекопировать содержимое пакета в свою память и переслать его далее, после чего освободить пакет. Вот как будет это выглядеть в коде:

PADAPT pAdapt = (PADAPT)MiniportAdapterContext;

Контекст адаптера приходящий в качестве параметра. Присвоим его своему типизированному указателю.

NDIS_STATUS Status;

Возвращаемый статус.

PNDIS_PACKET MyPacket;

Наш пакет – пока только указатель.

PRSVD Rsvd;

Резервный указатель.

PVOID MediaSpecificInfo = NULL;

Тип адаптера с которым будем работать.

ULONG MediaSpecificInfoSize = 0;

Размер типа адаптера.

ASSERT (pAdapt-gt;pSecondaryAdapt);

pAdapt = pAdapt-gt;pSecondaryAdapt;

Проверка наличия второго сетевого адаптера. Вверху я говорил, что его наличие необходимо предусматривать.

if (IsIMDeviceStateOn (pAdapt) == FALSE) {

 return NDIS_STATUS_FAILURE;

}

Проверка наличия и состояния.

NdisAllocatePacket(amp;Status, amp;MyPacket, pAdapt-gt;SendPacketPoolHandle);

Выделение места под размер полученного пакета (Pool) данных.

if (Status == NDIS_STATUS_SUCCESS) {

 PNDIS_PACKET_EXTENSION Old, New;

 Rsvd = (PRSVD)(MyPacket-gt;ProtocolReserved);

 Rsvd-gt;OriginalPkt = Packet;

 MyPacket-gt;Private.Flags = Flags;

 MyPacket-gt;Private.Head = Packet-gt;Private.Head;

 MyPacket-gt;Private.Tail = Packet-gt;Private.Tail;

Собственно копирование всей служебной информации

NdisSetPacketFlags(MyPacket, NDIS_FLAGS_DONT_LOOPBACK);

Установка ее в наш внутренний буфер.

NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(MyPacket), NDIS_OOB_DATA_FROM_PACKET(Packet), sizeof(NDIS_PACKET_OOB_DATA));

Перенос данных в сам пакет.

NdisIMCopySendPerPacketInfo(MyPacket, Packet);

Копирование служебных данных по пересылке пакета.

Копирование данных о типе адаптера, куда пересылать данные.

NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(Packet, amp;MediaSpecificInfo, amp;MediaSpecificInfoSize);

if (MediaSpecificInfo || MediaSpecificInfoSize) {

 NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(MyPacket, MediaSpecificInfo, MediaSpecificInfoSize);

}

Собственно пересылка имеющихся данных в NDIS, что вызовет нормальное прохождение пакета далее по цепочке драйверов.

NdisSend(amp;Status, pAdapt-gt;BindingHandle, MyPacket);

if (Status != NDIS_STATUS_PENDING) {

 NdisIMCopySendCompletePerPacketInfo (Packet, MyPacket);

 NdisFreePacket(MyPacket);

}

Если нет задержки на отсылке освободить пакет.

} else {

Это говорит об отсутствии пакета в системе – ничего не надо делать.

}

return(Status);

Возврат значения SUCCESS или код ошибки.

Стоит остановиться еще на одном моменте. Когда система ответила, что посылка данных закончена кодом задержки пакета – NDIS_STATUS_PENDING.

В этом случае мы пакет не освободим, блокировав таким образом всю систему NDIS по пересылке данных. Такое случается при посылке по медленной сети большого числа пакетов.

Как нам освободить пакет? Система предусматривает такое и при освобождении ресурса после освобождению пакета вызовет функцию из группы протокола PtSendComplete. Смена на протокольную группу вызвана тем, что система получит сообщение от низлежащего драйвера, что вызывает обращение именно к этой группе.

В данной функции, код которой идет следом мы увидим параметры в которых нам передадут контекст операции Send и адаптера, в результате чего мы получим возможность вызвать функцию NdisMSendComplete после NdisDprFreePacket и освободить NDIS для передачи нам следующих пакетов.

{

 PADAPT pAdapt =(PADAPT)ProtocolBindingContext;

 PNDIS_PACKET Pkt;

 PRSVD Rsvd;

 pAdapt = pAdapt-gt;pPrimaryAdapt;

 Rsvd =(PRSVD)(Packet-gt;ProtocolReserved);

 Pkt = Rsvd-gt;OriginalPkt;

 NdisIMCopySendCompletePerPacketInfo(Pkt, Packet);

 NdisDprFreePacket(Packet);

 NdisMSendComplete(pAdapt-gt;MiniportHandle, Pkt, Status);