Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: NDIS. Отправка пакета.  (Прочитано 20892 раз)
0 Пользователей и 1 Гость смотрят эту тему.
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
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #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 уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
afonin
Гость
« Ответ #2 : 26-08-2009 07:01 » 

Цитата
обратите внимание на строчку "#ifndef WIN9X". возможно траблы в этом?

Да, это я лоханулся. Прочитал как #ifdef и удалил за ненадобностью.
Но проблема не в этом.
Bug Check Code: DRIVER_IRQL_NOT_LESS_OR_EQUAL
Использую где нельзя страничную память?
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #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 уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #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 уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
afonin
Гость
« Ответ #5 : 26-08-2009 11:30 » 

Сейчас восстановил оригинальный код.
Добавил отправку пакета - результат тот же.
Причем когда этот код работает в MPSendPackets все ОК. (т.е. пакет пришел от вышележащего драйвера, я его анализирую, изменяю и отправляю в сеть)

А вот когда я пытаюсь пришедший из сети пакет в функции PtReceivePacket отправить обратно в сеть - проблема.
Может быть нельзя отправлять пакеты из PtReceivePacket?
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 27-08-2009 05:59 » 

а на каком они IRQL выполняются? MPSendPackets и PtReceivePacket
Записан

RTFM уже хоть раз наконец!  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
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #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 уже хоть раз наконец!  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
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #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 уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #12 : 28-08-2009 07:14 » 

afonin, а в NDIS драйвере  вообще есть собственная нить или запустить ее можно? или может быть есть какие нибудь отложенные функции? (в качестве альтернативы отсылки пакетов)

хотя по списку используемых функций - они вроде все на должны работать...
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
afonin
Гость
« Ответ #13 : 31-08-2009 09:56 » 

Короче для "своих" пакетов не надо вызывать NdisMSendComplete в функции PtSendComplete.
Осталось только научиться их отличать.
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #14 : 02-09-2009 10:15 » 

а кстати где об этом сказано? а то не нашел пока...
Записан

RTFM уже хоть раз наконец!  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
Участник

ru
Offline Offline

« Ответ #16 : 06-11-2010 02:24 » new

Короче для "своих" пакетов не надо вызывать NdisMSendComplete в функции PtSendComplete.
Осталось только научиться их отличать.

А если надо послать второй пакет, а статус(логический) будет все еще в NDIS_STATUS_PENDING? Думается, что послать второй пакет в этом случае не получится, т.о. надо как-то отслеживать завершение работы своего NDisSend. Что предлагается?


PS додумал сам, поскольку в PtSendComplete наш пакет определен, то надо просто менять флаг, разрешающий отправку следующего пакета.
« Последнее редактирование: 06-11-2010 02:29 от supermaxus » Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines