Група мініпорт
Функції цієї групи займаються обробкою потоку даних і подій, що відбуваються в верхньому рівні драйвера, і викликаються зверненням до NDIS TCP / IP стека.
Якщо подивитися на схеми з другої частини, то видно, що в нижній частині знаходяться функції протоколу, а у верхній мініпорт. Чому? Кожен драйвер виступає в двох іпостасях. Спілкуючись з верхнім рівнем драйверів він ставати для нього драйвером мініпорт, а для нижнього рівня, драйвером протоколу.
Список функцій мініпорт:
MPInitialize - ініціалізація групи.
Функції відповідають за пересилку пакетів даних.
Функції роботи з харчуванням станом системи і системою PlagNPlay. Сказати особливо нема чого. Стандартне відстеження внутрішніх подій системи прописане Microsoft.
MPHalt - відпрацювання вивантаження і де реєстрації драйвера при аварійному.
MPReset - як написано у Microsoft - ми не повинні нічого робити :)
Робота з системою - необхідність відпрацьовувати події важливі для сервісу коректно.
В системі може бути не один адаптер і відповідно не один драйвер до якого доводиться звертатися. У разі такого використовуються ці функції.
У нашому випадку основними функціями з цієї групи - є функції пересилання даних. Всі інші ми можемо не розглядати, їх призначення - обслуговувати правильно системні зв'язки, вся основна частина яких написана Microsoft.
Основна функція викликається завжди, при проходженні даних. За правилами роботи з даними в NDIS необхідно написати (що в прикладі і зроблено) re-wrap пакету.
Для цього спочатку пакет треба захопити, перекопіювати вміст пакета в свою пам'ять і переслати його далі, після чого звільнити пакет. Ось як буде це виглядати в коді:
PADAPT pAdapt = (PADAPT) MiniportAdapterContext;
Контекст адаптера приходить в якості параметра. Дамо його своєму типізовану вказівником.
Наш пакет - поки тільки покажчик.
PVOID MediaSpecificInfo = NULL;
Тип адаптера з яким будемо працювати.
ULONG MediaSpecificInfoSize = 0;
Розмір типу адаптера.
Перевірка наявності другого мережевого адаптера. Вгорі я говорив, що його наявність необхідно передбачати.
if (IsIMDeviceStateOn (pAdapt) == FALSE)
Перевірка наявності та стану.
NdisAllocatePacket (Status, MyPacket, pAdapt-> SendPacketPoolHandle);
Виділення місця під розмір отриманого пакета (Pool) даних.
if (Status == NDIS_STATUS_SUCCESS)
PNDIS_PACKET_EXTENSION Old, New;
Установка її в наш внутрішній буфер.
NdisMoveMemory (NDIS_OOB_DATA_FROM_PACKET (MyPacket), NDIS_OOB_DATA_FROM_PACKET (Packet), sizeof (NDIS_PACKET_OOB_DATA));
Перенесення даних в сам пакет.
NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO (Packet, MediaSpecificInfo, MediaSpecificInfoSize);
if (MediaSpecificInfo || MediaSpecificInfoSize)
NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO (MyPacket, MediaSpecificInfo, MediaSpecificInfoSize);
Власне пересилання наявних даних в NDIS, що викличе нормальне проходження пакета далі по ланцюжку драйверів.
NdisSend (Status, pAdapt-> BindingHandle, MyPacket);
if (Status! = NDIS_STATUS_PENDING)
Якщо немає затримки на відсилання звільнити пакет.
Це говорить про відсутність пакету в системі - нічого не треба робити.
Повернення значення SUCCESS або код помилки.
Варто зупинитися ще на одному моменті. Коли система відповіла, що посилка даних закінчена кодом затримки пакета - NDIS_STATUS_PENDING.
В цьому випадку ми пакет не звільнимо, блокувавши таким чином всю систему NDIS з пересилання даних. Таке трапляється при посилці по повільній мережі великого числа пакетів.
Як нам звільнити пакет? Система передбачає таке і при звільненні ресурсу після звільнення пакета викличе функцію з групи протоколу PtSendComplete. Зміна на протокольну групу викликана тим, що система отримає повідомлення від низлежащего драйвера, що викликає звернення саме до цієї групи.
У даній функції, код якої йде слідом ми побачимо параметри в яких нам передадуть контекст операції Send і адаптера, в результаті чого ми отримаємо можливість викликати функцію NdisMSendComplete після NdisDprFreePacket і звільнити NDIS для передачі нам наступних пакетів.
PADAPT pAdapt = (PADAPT) ProtocolBindingContext;