IM NDIS

Тема в разделе "WASM.NETWORKS", создана пользователем new_s, 2 май 2006.

  1. new_s

    new_s New Member

    Публикаций:
    0
    Регистрация:
    20 авг 2005
    Сообщения:
    16
    Адрес:
    Беларусь
    Не могу разобраться как достать Ip пришедшего пакета.
     
  2. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    В ProtocolReceive() и ProtocolReceivePacket():

    Ip пакета = (char *)<Адрес пакета> + <размер MAC Header 14 байт> + <смещение адреса 12 байт>
     
  3. new_s

    new_s New Member

    Публикаций:
    0
    Регистрация:
    20 авг 2005
    Сообщения:
    16
    Адрес:
    Беларусь
    не совсем ясно.

    можно подробнее.

    адрес пакета --- LookAheadBuffer
     
  4. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    В примере в приложении выполняется копирование принятого пакета.

    MyPacket в строках
    Код (Text):
    1. // Добавить пакет в очередь на обработку
    2. if (PacketFromQueue = AddNdisPacketToQueue(&WaitUpQueue, MyPacket))
    - копия PNDIS_PACKET, причем все данные содержатся в одном единственном буфере и для доступа к самому содержимому пакета теперь достаточно вызвать
    Код (Text):
    1. PNDIS_BUFFER lpBuffer;
    2. NdisQueryPacket(MyPacket, NULL, NULL, &lpBuffer, NULL);
    В lpBuffer будет указатель на первый буфер PNDIS_PACKET. Так как буфер всего один, то он и будет пакетом MAC-уровня. Дальше как в предыдущем посте.

    [​IMG] 972573851__code.c
     
  5. new_s

    new_s New Member

    Публикаций:
    0
    Регистрация:
    20 авг 2005
    Сообщения:
    16
    Адрес:
    Беларусь
    В passthru вроде тоже сначала копируется пакет а затем отсылается. Зачем тогда в примере столько кода?

    Наверно не до конца понимаю сам процесс.

    Появился пакет вызывается ptreceive или ptreceivepacket.

    Мы получаем в функции указатель на буфер ndis. Но помимо нужного нам пакета mac уровня(т.е. самих данных) в полученном буфере лежит ещё много чего. Ещё полученный буфер может быть разбит. В итоге мы должны получить указатель на целый буфер mac уровня и оттуда извлечь ip.

    Поправте если не прав.

    P.S.

    А нет ли простого примера полностью рабочего?
     
  6. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    Появился пакет вызывается ptreceive или ptreceivepacket.

    Мы получаем в функции указатель на буфер ndis. Но помимо нужного нам пакета mac уровня(т.е. самих данных) в полученном буфере лежит ещё много чего.




    Только получаем указатель PNDIS_PACKET, а не на буфер. В NDIS_PACKET еще много всякого добра спрятано, из него ценным является буфер с данными (обычная структура MDL).



    Ещё полученный буфер может быть разбит. В итоге мы должны получить указатель на целый буфер mac уровня и оттуда извлечь ip.



    MDL хранит данные по кускам, в виде отдельных буферов. Чтобы нормально работать с пакетом их проще всего перелить в один непрерывный буфер. В passthru это не делается, потому что он просто перенаправляет полученный пакет наверх, а с этими буферами разбирается уже драйвер tcp/ip. Дальше из непрерывного буфера получаем сам пакет с помощью NdisQueryPacket(). Если пакет нужно заблокировать, после анализа просто чистим выделенные ресурсы. Если его нужно отправить наверх, то как в passthru вызывается NdisMIndicateReceivePacket().



    Код выдрал из рабочей программы, поэтому в нем есть немного лишних действий с очередями пакетов, в остальном он делает то, что написано. Простой рабочий пример это passthru.
     
  7. Noah

    Noah New Member

    Публикаций:
    0
    Регистрация:
    14 мар 2006
    Сообщения:
    5
    Адрес:
    Russia
    Просто 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
     
  8. Noah

    Noah New Member

    Публикаций:
    0
    Регистрация:
    14 мар 2006
    Сообщения:
    5
    Адрес:
    Russia
    А что касается расположения 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 заголовок.
     
  9. new_s

    new_s New Member

    Публикаций:
    0
    Регистрация:
    20 авг 2005
    Сообщения:
    16
    Адрес:
    Беларусь
    Т.е. чтобы сильно не мучаться с добыванием ip адреса

    лучше отказаться от PtrReceive, а использовать

    PtReceivePacket, в которой необходимо вызвать UNILReadOnPacket. В буфере который придёт из функции надо сдвинуться на mac адрес и можно читать ip?

    ip = ((PIP_HEADER)lpBuffer+14)->IP_DST_IP;

    Поправте.
     
  10. Noah

    Noah New Member

    Публикаций:
    0
    Регистрация:
    14 мар 2006
    Сообщения:
    5
    Адрес:
    Russia
    Нет, по-хорошему надо обрабатывать данные и в PtReceive и в PtReceivePacket.

    Поставь DbgPrint внутрь этих двух функций и увидишь, что гораздо чаще вызывается PtReceive. Если ты хочешь вообще из проги убрать PtReceive - то ничего не получится. Спецификация NDIS требует обязательной регистрации ReceiveHandler'а.

    Некоторое время назад видел я в нете исходник passthru с нормальной функциональностью, с объектом устройства и с корректной обработкой пакетов. Видел на pcausa.com. Поищи там.