В ProtocolReceive() и ProtocolReceivePacket(): Ip пакета = (char *)<Адрес пакета> + <размер MAC Header 14 байт> + <смещение адреса 12 байт>
В примере в приложении выполняется копирование принятого пакета. MyPacket в строках Код (Text): // Добавить пакет в очередь на обработку if (PacketFromQueue = AddNdisPacketToQueue(&WaitUpQueue, MyPacket)) - копия PNDIS_PACKET, причем все данные содержатся в одном единственном буфере и для доступа к самому содержимому пакета теперь достаточно вызвать Код (Text): PNDIS_BUFFER lpBuffer; NdisQueryPacket(MyPacket, NULL, NULL, &lpBuffer, NULL); В lpBuffer будет указатель на первый буфер PNDIS_PACKET. Так как буфер всего один, то он и будет пакетом MAC-уровня. Дальше как в предыдущем посте. 972573851__code.c
В passthru вроде тоже сначала копируется пакет а затем отсылается. Зачем тогда в примере столько кода? Наверно не до конца понимаю сам процесс. Появился пакет вызывается ptreceive или ptreceivepacket. Мы получаем в функции указатель на буфер ndis. Но помимо нужного нам пакета mac уровня(т.е. самих данных) в полученном буфере лежит ещё много чего. Ещё полученный буфер может быть разбит. В итоге мы должны получить указатель на целый буфер mac уровня и оттуда извлечь ip. Поправте если не прав. P.S. А нет ли простого примера полностью рабочего?
Появился пакет вызывается ptreceive или ptreceivepacket. Мы получаем в функции указатель на буфер ndis. Но помимо нужного нам пакета mac уровня(т.е. самих данных) в полученном буфере лежит ещё много чего. Только получаем указатель PNDIS_PACKET, а не на буфер. В NDIS_PACKET еще много всякого добра спрятано, из него ценным является буфер с данными (обычная структура MDL). Ещё полученный буфер может быть разбит. В итоге мы должны получить указатель на целый буфер mac уровня и оттуда извлечь ip. MDL хранит данные по кускам, в виде отдельных буферов. Чтобы нормально работать с пакетом их проще всего перелить в один непрерывный буфер. В passthru это не делается, потому что он просто перенаправляет полученный пакет наверх, а с этими буферами разбирается уже драйвер tcp/ip. Дальше из непрерывного буфера получаем сам пакет с помощью NdisQueryPacket(). Если пакет нужно заблокировать, после анализа просто чистим выделенные ресурсы. Если его нужно отправить наверх, то как в passthru вызывается NdisMIndicateReceivePacket(). Код выдрал из рабочей программы, поэтому в нем есть немного лишних действий с очередями пакетов, в остальном он делает то, что написано. Простой рабочий пример это passthru.
Просто passthru - далеко не рабочий пример. В случае, если был вызван ReceivePacketHandler, то проблем действительно никаких нет: VOID UTILReadOnPacket( IN PNDIS_PACKET Packet, OUT PUCHAR lpBuffer, IN ULONG nNumberOfBytesToRead, IN ULONG nOffset, OUT PULONG lpNumberOfBytesRead ) /*++ Описание: Функция, осуществляющая фактическое чтение данных из пакета. Аргументы: Packet Указетель на пакет, из которого читаются данные lpBuffer Буфер, в который необходимо поместить прочитанные данные nNumberOfBytesToRead Сколько байт прочитать в буфер nOffset Смещение от начала пакета, с которого производить чтение lpNumberOfBytesRead Сколько байт реально прочитано Возвращаемое значение: Через lpNumberOfBytesRead возвращается количество прочитанных байт из пакета --*/ { PNDIS_BUFFER CurrentBuffer; UINT nBufferCount, TotalPacketLength; PUCHAR VirtualAddress; UINT CurrentLength, CurrentOffset; UINT AmountToMove; *lpNumberOfBytesRead = 0; if (!nNumberOfBytesToRead) return; // // Опрашиваем пакет // NdisQueryPacket( (PNDIS_PACKET )Packet, (PUINT )NULL, // Physical Buffer Count (PUINT )&nBufferCount, // Buffer Count &CurrentBuffer, // First Buffer &TotalPacketLength // TotalPacketLength ); // // Опрашиваем первый буфер // NdisQueryBuffer( CurrentBuffer, &VirtualAddress, &CurrentLength ); CurrentOffset = 0; while( nOffset || nNumberOfBytesToRead ) { while( !CurrentLength ) { NdisGetNextBuffer( CurrentBuffer, &CurrentBuffer ); if (!CurrentBuffer) return; NdisQueryBuffer( CurrentBuffer, &VirtualAddress, &CurrentLength ); CurrentOffset = 0; } if( nOffset ) { // Считаем, сколько байт нужно переместить из этого буфера if( CurrentLength > nOffset ) CurrentOffset = nOffset; else CurrentOffset = CurrentLength; nOffset -= CurrentOffset; CurrentLength -= CurrentOffset; } if( nOffset ) { CurrentLength = 0; continue; } if( !CurrentLength ) { continue; } // Считаем, сколько байт нужно переместить из этого буфера if (CurrentLength > nNumberOfBytesToRead) AmountToMove = nNumberOfBytesToRead; else AmountToMove = CurrentLength; // Копируем данные NdisMoveMemory( lpBuffer, &VirtualAddress[ CurrentOffset ], AmountToMove ); // сдвигаем указатель lpBuffer += AmountToMove; // обновляем счетчики *lpNumberOfBytesRead +=AmountToMove; nNumberOfBytesToRead -=AmountToMove; CurrentLength = 0; } } А вот если вызвается ReceiveHandler - то тогда, хорошо, если туда придет хотя бы TCP заголовок. Впрочем, насколько я помню, IP адрес в LookAheadBuffer всегда попадал. Однако, чтобы получить пакет целиком, придется еще passthru проапгрэйдить. А именно, внутри ReceiveHandler-а нужно вызывать NdisTransferData, после чего сформированный пакет можно будет получить в TransferDataCompleteHandler-е. PS. UTILReadOnPacket взят с ndis.com
А что касается расположения IP адреса в LookAheadBuffer'e, то... typedef struct _IP_HEADER { UCHAR IP_IPVER; UCHAR IP_SVCTYPE; __int16 IP_TLENGTH; __int16 IP_IDENT; __int16 IP_FRAG; UCHAR IP_TTL; UCHAR IP_PROTOCOL; __int16 IP_CHECKSUM; UINT IP_SRC_IP; UINT IP_DST_IP; } IP_HEADER, * PIP_HEADER; ip = ((PIP_HEADER)pLookAheadBuffer)->IP_DST_IP; Только в буффере, который вернет UTILReadOnPacket будет еще и MAC заголовок.
Т.е. чтобы сильно не мучаться с добыванием ip адреса лучше отказаться от PtrReceive, а использовать PtReceivePacket, в которой необходимо вызвать UNILReadOnPacket. В буфере который придёт из функции надо сдвинуться на mac адрес и можно читать ip? ip = ((PIP_HEADER)lpBuffer+14)->IP_DST_IP; Поправте.
Нет, по-хорошему надо обрабатывать данные и в PtReceive и в PtReceivePacket. Поставь DbgPrint внутрь этих двух функций и увидишь, что гораздо чаще вызывается PtReceive. Если ты хочешь вообще из проги убрать PtReceive - то ничего не получится. Спецификация NDIS требует обязательной регистрации ReceiveHandler'а. Некоторое время назад видел я в нете исходник passthru с нормальной функциональностью, с объектом устройства и с корректной обработкой пакетов. Видел на pcausa.com. Поищи там.