afonin
Гость
|
|
« : 25-08-2009 14:08 » |
|
Господа, разбираюсь с passthru. C переменным успехом. Написал в PtReceivePacket код, анализирующий протокол, и если это ARP, пытаюсь отправить его обратно в сеть. PNDIS_PACKET Pack2; if(reverse_us(peth->ether_type) == 0x0806) // ARP { NdisAllocatePacket(&Status, &Pack2, pAdapt->SendPacketPoolHandle);
if (Status == NDIS_STATUS_SUCCESS) { PSEND_RSVD SendRsvd;
SendRsvd = (PSEND_RSVD)(Pack2->ProtocolReserved); SendRsvd->OriginalPkt = Packet;
Pack2->Private.Flags = NdisGetPacketFlags(Packet);
NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(Packet, &MediaSpecificInfo, &MediaSpecificInfoSize);
if (MediaSpecificInfo || MediaSpecificInfoSize) { NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(Pack2, MediaSpecificInfo, MediaSpecificInfoSize); }
NdisAllocateBufferPool(&Status, &PoolHandle, 1); DBGPRINT(("PtReceivePacket: Status = %d\n", Status));
DBGPRINT(("PtReceivePacket: NdisAllocateBuffer\n")); NdisAllocateBuffer(&Status, &NdisBufAdd, PoolHandle, buf, NumberOfBytes);
DBGPRINT(("PtReceivePacket: NdisChainBufferAtBack\n")); NdisChainBufferAtFront(Pack2, NdisBufAdd);
GetBufFromPacket(Pack2, buf, sizeof(buf), &NumberOfBytes);
DBGPRINT(("PtReceivePacket: Send from recieve!!!\n")); PrintBufer(buf, NumberOfBytes);
//_asm {int 3}; NdisSend(&Status, pAdapt->BindingHandle, Pack2);
if (Status != NDIS_STATUS_PENDING) { NdisFreePacket(Pack2); }
//return 0; } }
VOID PtSendComplete(IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET Packet, IN NDIS_STATUS Status ) { PADAPT pAdapt =(PADAPT)ProtocolBindingContext; PNDIS_PACKET Pkt; NDIS_HANDLE PoolHandle; ULONG NumberOfBytes; UCHAR buf[1518]; UINT index = 0;
#ifdef NDIS51 PoolHandle = NdisGetPoolFromPacket(Packet); if (PoolHandle != pAdapt->SendPacketPoolHandle) { DBGPRINT(("PtSendComp: Adapt %p, Stacked Packet %p\n", pAdapt, Packet));
NdisMSendComplete(pAdapt->MiniportHandle, Packet, Status); DBGPRINT(("\nPtSendComp: After NdisMSendComplete. Status = %d\n", Status)); } else #endif // NDIS51 { PSEND_RSVD SendRsvd;
SendRsvd = (PSEND_RSVD)(Packet->ProtocolReserved); Pkt = SendRsvd->OriginalPkt; DBGPRINT(("\nPtSendComp: Befor NdisDprFreePacket\n")); NdisDprFreePacket(Packet);
DBGPRINT(("\nPtSendComp: Befor NdisMSendComplete\n")); NdisMSendComplete(pAdapt->MiniportHandle, Pkt, Status); } DBGPRINT(("\nPtSendComp: EXIT")); }
Как я понял if (PoolHandle != pAdapt->SendPacketPoolHandle) разделяет пакеты, пришедшие от вышележащих драйверов и созданные мной. Когда я попадаю в else, получаю BSOD на NdisMSendComplete. Подскажите, что не так и куда копать.
|
|
« Последнее редактирование: 06-09-2009 16:24 от Sel »
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #1 : 25-08-2009 17:15 » |
|
в примере C:\DDK\6001.18001\src\network\ndis\passthru\driver\protocol.c приведен несколько другой код обработки. VOID PtSendComplete( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET Packet, IN NDIS_STATUS Status ) /*++
Routine Description:
Called by NDIS when the miniport below had completed a send. We should complete the corresponding upper-edge send this represents.
Arguments:
ProtocolBindingContext - Points to ADAPT structure Packet - Low level packet being completed Status - status of send
Return Value:
None
--*/ { PADAPT pAdapt = (PADAPT)ProtocolBindingContext; PNDIS_PACKET Pkt; NDIS_HANDLE PoolHandle;
#ifdef NDIS51 // // Packet stacking: // // Determine if the packet we are completing is the one we allocated. If so, then // get the original packet from the reserved area and completed it and free the // allocated packet. If this is the packet that was sent down to us, then just // complete it // PoolHandle = NdisGetPoolFromPacket(Packet); if (PoolHandle != pAdapt->SendPacketPoolHandle) { // // We had passed down a packet belonging to the protocol above us. // // DBGPRINT(("PtSendComp: Adapt %p, Stacked Packet %p\n", pAdapt, Packet));
NdisMSendComplete(pAdapt->MiniportHandle, Packet, Status); } else #endif // NDIS51 { PSEND_RSVD SendRsvd;
SendRsvd = (PSEND_RSVD)(Packet->ProtocolReserved); Pkt = SendRsvd->OriginalPkt; #ifndef WIN9X NdisIMCopySendCompletePerPacketInfo (Pkt, Packet); #endif NdisDprFreePacket(Packet);
NdisMSendComplete(pAdapt->MiniportHandle, Pkt, Status); } // // Decrease the outstanding send count // ADAPT_DECR_PENDING_SENDS(pAdapt); }
обратите внимание на строчку "#ifndef WIN9X". возможно траблы в этом? а вобще я ничего в этом не смыслю)))
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
afonin
Гость
|
|
« Ответ #2 : 26-08-2009 07:01 » |
|
обратите внимание на строчку "#ifndef WIN9X". возможно траблы в этом?
Да, это я лоханулся. Прочитал как #ifdef и удалил за ненадобностью. Но проблема не в этом. Bug Check Code: DRIVER_IRQL_NOT_LESS_OR_EQUAL Использую где нельзя страничную память?
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #3 : 26-08-2009 08:04 » |
|
не факт. этот баг не относится к использовании памяти. его надо понимать дословно - вызов функции на завышенном IRQL. такая ошибка может быть следствием более раннего вызова функции. м может быть следствием неправильной инициализации пакета. например "Callers of NdisSend run at IRQL <= DISPATCH_LEVEL." например, вы во всем коде, видимо, "#ifndef WIN9X" игнорировали... а ведь там #ifndef WIN9X NdisIMCopySendPerPacketInfo(MyPacket, Packet); #endif
перед NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO и NdisSend() и еще много чего... повнимательней пройдитесь. у вас код без ваших дополнений - был работоспособен?)
|
|
« Последнее редактирование: 26-08-2009 08:06 от Ochkarik »
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
Ochkarik
|
|
« Ответ #4 : 26-08-2009 08:23 » |
|
кстати там пример кода отправки пакета был... чем не подошел?) NdisAllocatePacket(&Status, &MyPacket, pAdapt->SendPacketPoolHandle);
if (Status == NDIS_STATUS_SUCCESS) { PSEND_RSVD SendRsvd;
// // Save a pointer to the original packet in our reserved // area in the new packet. This is needed so that we can // get back to the original packet when the new packet's send // is completed. // SendRsvd = (PSEND_RSVD)(MyPacket->ProtocolReserved); SendRsvd->OriginalPkt = Packet;
NdisGetPacketFlags(MyPacket) = Flags;
// // Set up the new packet so that it describes the same // data as the original packet. // NDIS_PACKET_FIRST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(Packet); NDIS_PACKET_LAST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(Packet); #ifdef WIN9X // // Work around the fact that NDIS does not initialize this // to FALSE on Win9x. // NDIS_PACKET_VALID_COUNTS(MyPacket) = FALSE; #endif
// // Copy the OOB Offset from the original packet to the new // packet. // NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(MyPacket), NDIS_OOB_DATA_FROM_PACKET(Packet), sizeof(NDIS_PACKET_OOB_DATA));
#ifndef WIN9X // // Copy the right parts of per packet info into the new packet. // This API is not available on Win9x since task offload is // not supported on that platform. // NdisIMCopySendPerPacketInfo(MyPacket, Packet); #endif // // Copy the Media specific information // NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(Packet, &MediaSpecificInfo, &MediaSpecificInfoSize);
if (MediaSpecificInfo || MediaSpecificInfoSize) { NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(MyPacket, MediaSpecificInfo, MediaSpecificInfoSize); }
NdisSend(&Status, pAdapt->BindingHandle, MyPacket);
if (Status != NDIS_STATUS_PENDING) { #ifndef WIN9X NdisIMCopySendCompletePerPacketInfo (Packet, MyPacket); #endif NdisFreePacket(MyPacket); ADAPT_DECR_PENDING_SENDS(pAdapt); }
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
afonin
Гость
|
|
« Ответ #5 : 26-08-2009 11:30 » |
|
Сейчас восстановил оригинальный код. Добавил отправку пакета - результат тот же. Причем когда этот код работает в MPSendPackets все ОК. (т.е. пакет пришел от вышележащего драйвера, я его анализирую, изменяю и отправляю в сеть)
А вот когда я пытаюсь пришедший из сети пакет в функции PtReceivePacket отправить обратно в сеть - проблема. Может быть нельзя отправлять пакеты из PtReceivePacket?
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #6 : 27-08-2009 05:59 » |
|
а на каком они IRQL выполняются? MPSendPackets и PtReceivePacket
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
afonin
Гость
|
|
« Ответ #7 : 27-08-2009 09:12 » |
|
В MPSendPackets IRQL = 0; В PtReceivePacket IRQL = 2; Но в обоих случаях в PtSendComplete IRQL = 2, а падает именно там. Пробовал в PtReceivePacket понижать IRQL до 0 на время отправки: KeRaiseIrql(0, &old_irql); ......................................... NdisSend(&Status, pAdapt->BindingHandle, Pack2); KeLowerIrql(old_irql);
не помогло. Так же валится в PtSendComplete на вызове функции NdisMSendComplete(pAdapt->MiniportHandle, Pkt, Status);
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #8 : 27-08-2009 14:53 » |
|
эээ! что за грубости...)))) ежели система выставляет свой IQRL на DISPATCH_LEVEL - значит это кому нибудь надо?! никогда так не делайте) тем более вы это сделали неправильно... IRQL=0 - это PASSIVE_LEVEL - самый низкий уровень. на нем возможны переключения контекста(читай - процессов). IRQL=2 - это DISPATCH_LEVEL - на этом уровне планировщику потоков запрещена смена контекста(выполняется текущий поток и он не может быть вытеснен, пока IRQL не опустится). между ними еще есть APC_LEVEL=1. переключение контекстов на этом уровне работает, используется он для синхронизации APC(асинхронных) процедур.
функция KeRaiseIrql - ПОВЫШАЕТ IRQL. а вы пишете NewIrql=0. "If the new IRQL is less than the current IRQL, a bug check occurs." это раз. второе - даже не пытайтесь понизить текущий IRQL, если повышали его не вы-же. если система его решила повысить, то это сделано не просто так, а для синхронизации каких-то процессов. вы просто завалите систему и сами не поймете что это ваша вина. причем проявлятся это может очень нестабильно) такие баги хуже всего отлавливать.
и кстати в NDIS видимо не стоит использовать функции называющихся иначе чем на Ndis***. это для совместимости. говорят ndis портируется под другие платформы...
функции KeRaiseIrql/KeLowerIrql используются, если вам ОООЧЕНЬ надо сделать синхронизацию процессов которую иначе сделать невозможно. в остальных случаях - это дурной тон. это как... видел я програмку весь код которой был помещен в __try{} ))) ..................... так... вот что странно: MChars.SendPacketsHandler = MPSendPackets; который обязан быть "The MiniportSendPackets function of a serialized miniport driver runs at IRQL = DISPATCH_LEVEL."
и PChars.ReceivePacketHandler = PtReceivePacket; который тоже "ProtocolReceivePacket runs at IRQL = DISPATCH_LEVEL." а в измеренных величинах стоят 0 и 2, когда должно быть в обоих случаях 2? что то тут не так...
теперь насчет кода. откуда у вас в PtReceivePacket переменная PoolHandle взялась? видимо код вы привели не весь) ищите что вы вписали еще такого, чей IRQL не совпадает с нужным. ошибка может быть не в NdisMSendComplete а значительно раньше.
PS кстати я ввиду незнания NDIS... не уверен - а это вобще правильно так отсылать?) или какой то другой метод есть... PPS и еще цитата DDK "The IRQL at which a driver function runs affects which NDIS functions it can call. Certain functions can only be called at IRQL = PASSIVE_LEVEL. Others can be called at DISPATCH_LEVEL or lower. A driver writer should check every NDIS function for IRQL restrictions."
|
|
« Последнее редактирование: 27-08-2009 14:56 от Ochkarik »
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
afonin
Гость
|
|
« Ответ #9 : 28-08-2009 05:55 » |
|
эээ! что за грубости...)))) ежели система выставляет свой IQRL на DISPATCH_LEVEL - значит это кому нибудь надо?!
Да я вроде понимаю, что нехорошо. Просто в качестве эксперимента. MChars.SendPacketsHandler = MPSendPackets; который обязан быть "The MiniportSendPackets function of a serialized miniport driver runs at IRQL = DISPATCH_LEVEL."
А есть еще такая строчка: The MiniportSendPackets function of a deserialized miniport driver can be called at any IRQL <= DISPATCH_LEVEL PS кстати я ввиду незнания NDIS... не уверен - а это вобще правильно так отсылать?) или какой то другой метод есть... Так и я не уверен. Цель - проанализировать трафик и при определенных условиях послать новый пакет в сеть. Вопрос как правильно реализовать эту задачу?
|
|
|
Записан
|
|
|
|
afonin
Гость
|
|
« Ответ #10 : 28-08-2009 06:02 » |
|
Может это: Callers of NdisMoveMemory can run at any IRQL if the given Source and Destination are resident. Otherwise, callers must be running at IRQL < DISPATCH_LEVEL, as, for example if either address is on the stack.
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #11 : 28-08-2009 06:58 » |
|
afonin, ну... а вы перемещаете свопируемые области? судя по всему нет... на DISPATCH_LEVEL обращение к свопируемой памяти запрещено. это те страницы памяти которые могут быть сброшены на диск. к остальной понятное дело можно...
не уверен, но у меня ощущение что в пакетах такой памяти быть не должно...
PS вот это "for example if either address is on the stack." не понял...
|
|
« Последнее редактирование: 28-08-2009 07:10 от Ochkarik »
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
Ochkarik
|
|
« Ответ #12 : 28-08-2009 07:14 » |
|
afonin, а в NDIS драйвере вообще есть собственная нить или запустить ее можно? или может быть есть какие нибудь отложенные функции? (в качестве альтернативы отсылки пакетов)
хотя по списку используемых функций - они вроде все на должны работать...
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
afonin
Гость
|
|
« Ответ #13 : 31-08-2009 09:56 » |
|
Короче для "своих" пакетов не надо вызывать NdisMSendComplete в функции PtSendComplete. Осталось только научиться их отличать.
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #14 : 02-09-2009 10:15 » |
|
а кстати где об этом сказано? а то не нашел пока...
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
afonin
Гость
|
|
« Ответ #15 : 02-09-2009 11:34 » |
|
NdisMSendComplete returns the packet and final status of a completed send request for which the driver previously returned NDIS_STATUS_PENDING.
То есть эту функцию нужно вызывать для того, чтобы вышележащий драйвер понял, что пакет обработан всеми нижними драйверами. После NdisMSendComplete в нашем драйвере верхний драйвер попадет в свою PtSendComplete. Если же пакет полностью наша придумка, то верхний драйвер ничего про него не знает.
|
|
|
Записан
|
|
|
|
supermaxus
Участник
Offline
|
|
« Ответ #16 : 06-11-2010 02:24 » |
|
Короче для "своих" пакетов не надо вызывать NdisMSendComplete в функции PtSendComplete. Осталось только научиться их отличать.
А если надо послать второй пакет, а статус(логический) будет все еще в NDIS_STATUS_PENDING? Думается, что послать второй пакет в этом случае не получится, т.о. надо как-то отслеживать завершение работы своего NDisSend. Что предлагается? PS додумал сам, поскольку в PtSendComplete наш пакет определен, то надо просто менять флаг, разрешающий отправку следующего пакета.
|
|
« Последнее редактирование: 06-11-2010 02:29 от supermaxus »
|
Записан
|
|
|
|
|