Win32 Raw Ethernet Programming / NPCap

274 views Asked by At

I need a good Win32 VC++ API for Raw Ethernet Programming.

I have written an application in VC++ win32 to communicate to a microcontroller having Gigabit Ethernet. Both windows side and microcontroller side software is written by me. The application is a CNC controller, so I need a high-speed, low-latency communication interface at a distance of 10 metres with superior noise immunity capabilities, and Ethernet just fits. Just to be clear, there is no TCP/IP layer, and the communication works on raw Ethernet II frames for low latency constraints.

Currently, I am using NPCap, and everything works OK, but there are some problems. First to use it from windows, NPCap drivers need to be installed to make it work on every PC. Second, the NPCap API seems underpowered for my needs. I don't know if I am using it correctly or not, but the API itself does not respond to high-performance IO requests. after writing some benchmarking tests. In a transmit test, the NPCap API managed a modest 3.2 Mbps with a packet size of 76 bytes. The receive test was not so accurate but was in the ballpark of 56 kbps speed, which just seems so wrong. Having said that, the latency is very good. When I wrote such a receive and transmit test on the microcontroller side, it went to a whooping 700 Mbps range, and my Windows task manager just lit up like Christmas.

The WireShark application, which I think is built on NPCap, does not feel so slow and seems to be able to capture all frames no matter what speed one throws at it. I don't know if I'm doing something wrong with NPCap, but here is the code for reference:

#include <pcap.h>
#pragma comment (lib, "Packet.lib")
#pragma comment (lib, "wpcap.lib")

#include <tchar.h>

BOOL LoadNpcapDlls()
{
    _TCHAR npcap_dir[512];
    UINT len;
    len = GetSystemDirectory(npcap_dir, 480);
    if (!len) {
        fprintf(stderr, "Error in GetSystemDirectory: %x", GetLastError());
        return FALSE;
    }
    _tcscat_s(npcap_dir, 512, _T("\\Npcap"));
    if (SetDllDirectory(npcap_dir) == 0) {
        fprintf(stderr, "Error in SetDllDirectory: %x", GetLastError());
        return FALSE;
    }
    return TRUE;
}

struct Ethernet
{
    pcap_t* handle;
    int8 Open()
    {
        char errbuf[PCAP_ERRBUF_SIZE];
        pcap_if_t* networkdevice;
        if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &networkdevice, errbuf) == -1)
            return -1;
        while (networkdevice != NULL)
        {
            String networkdevicedescription = networkdevice->description;
            String networkdevicetargettplink = "Network adapter 'TP-LINK Gigabit Ethernet USB Adapter' on local host";
            String networkdevicetargerealtek = "Network adapter 'Realtek Gaming GbE Family Controller' on local host";
            if (networkdevicedescription == networkdevicetargettplink)
            {
                if (LoadNpcapDlls() == 0)
                    return -3;
                handle = pcap_open_live(networkdevice->name, 65535, PCAP_OPENFLAG_PROMISCUOUS, 1, errbuf);
                if (handle == 0)
                    return -4;
                pcap_freealldevs(networkdevice);
                return 0;
            }if (networkdevicedescription == networkdevicetargerealtek)
            {
                if (LoadNpcapDlls() == 0)
                    return -3;
                handle = pcap_open_live(networkdevice->name, 65535, PCAP_OPENFLAG_PROMISCUOUS, 1, errbuf);
                if (handle == 0)
                    return -4;
                pcap_freealldevs(networkdevice);
                return 0;
            }
            networkdevice = networkdevice->next;
        }
        return -2;
    }
    char* Send(void* _data, uint32 lenght)
    {
        if (pcap_sendpacket(handle, (const uint8*)_data, lenght))
            return pcap_geterr(handle);
        return 0;
    }

    void* Recieve()
    {
        struct pcap_pkthdr* header = 0;
        const u_char* data = 0;
        pcap_next_ex(handle, &header, &data);
        return (void*)data;
    }
    void* Recieve(uint32 *bytes)
    {
        struct pcap_pkthdr* header = 0;
        const u_char* data = 0;
        pcap_next_ex(handle, &header, &data);
        *bytes = header->len;
        return (void*)data;
    }
    Ethernet()
    {
        ZeroMemory(this, sizeof(Ethernet));
    }
    ~Ethernet()
    {
        ZeroMemory(this, sizeof(Ethernet));
    }
};

Honestly I dont like this NPCap thing. Isn't there a native Win32 API like the Win32 socket programming API for raw Ethernet frames?

0

There are 0 answers