//------------------------------------------------------------------------------
tOplkError veth_init(const UINT8 aSrcMac_p[6])
{
    tOplkError      ret;
    struct ifreq    ifr;
    int             err;

    if ((vethInstance_l.fd = open(TUN_DEV_NAME, O_RDWR)) < 0)
    {
        DEBUG_LVL_VETH_TRACE("Error opening %s\n", TUN_DEV_NAME);
        return kErrorNoFreeInstance;
    }

    OPLK_MEMSET(&ifr, 0, sizeof(ifr));
    ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
    strncpy(ifr.ifr_name, PLK_VETH_NAME, IFNAMSIZ);

    if ((err = ioctl(vethInstance_l.fd, TUNSETIFF, (void*)&ifr)) < 0)
    {
        DEBUG_LVL_VETH_TRACE("Error setting TUN IFF options\n");
        close(vethInstance_l.fd);
        return err;
    }

    // save MAC address of TAP device and Ethernet device to be able to
    // exchange them
    OPLK_MEMCPY(vethInstance_l.macAdrs, aSrcMac_p, 6);
    getMacAdrs(vethInstance_l.tapMacAdrs);

    // start tap receive thread
    vethInstance_l.fStop = FALSE;
    if (pthread_create(&vethInstance_l.threadHandle, NULL, vethRecvThread, (void*)&vethInstance_l) != 0)
        return kErrorNoFreeInstance;

#if (defined(__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 12))
    pthread_setname_np(vethInstance_l.threadHandle, "oplk-veth");
#endif

    // register callback function in DLL
    ret = dllk_regAsyncHandler(receiveFrameCb);

    return ret;
}
//------------------------------------------------------------------------------
tOplkError edrv_init(const tEdrvInitParam* pEdrvInitParam_p)
{
    char                errorMessage[PCAP_ERRBUF_SIZE];
    char                aDevicePcapName[256];
    DWORD               threadId;

    // Check parameter validity
    ASSERT(pEdrvInitParam_p != NULL);

    // clear instance structure
    OPLK_MEMSET(&edrvInstance_l, 0, sizeof(edrvInstance_l));

    if (pEdrvInitParam_p->pDevName == NULL)
        return kErrorEdrvInit;

    // save the init data
    edrvInstance_l.initParam = *pEdrvInitParam_p;

    /* if no MAC address was specified read MAC address of used
     * Ethernet interface
     */
    if ((edrvInstance_l.initParam.aMacAddr[0] == 0) &&
        (edrvInstance_l.initParam.aMacAddr[1] == 0) &&
        (edrvInstance_l.initParam.aMacAddr[2] == 0) &&
        (edrvInstance_l.initParam.aMacAddr[3] == 0) &&
        (edrvInstance_l.initParam.aMacAddr[4] == 0) &&
        (edrvInstance_l.initParam.aMacAddr[5] == 0))
    {   // read MAC address from controller
        getMacAdrs(edrvInstance_l.initParam.pDevName,
                   edrvInstance_l.initParam.aMacAddr);
    }

    // Add string specific for WinPCap
    strcpy(aDevicePcapName, "\\Device\\NPF_");
    strcat(aDevicePcapName, edrvInstance_l.initParam.pDevName);
    edrvInstance_l.pPcap = pcap_open_live(
                        aDevicePcapName,
                        65535,  // snaplen
                        1,      // promiscuous mode
                        1,      // milliseconds read timeout
                        errorMessage
                    );

    if (edrvInstance_l.pPcap == NULL)
    {
        DEBUG_LVL_ERROR_TRACE("%s() Error!! Can't open pcap: %s\n", __func__, errorMessage);
        return kErrorEdrvInit;
    }

    // configure pcap for maximum responsiveness
    if (pcap_setmintocopy(edrvInstance_l.pPcap, 0) != 0)
    {
        DEBUG_LVL_ERROR_TRACE("pcap_setmintocopy failed\n");
    }

    // Initialize critical section
    InitializeCriticalSection(&edrvInstance_l.criticalSection);

    // Create the thread to begin execution on its own.
    edrvInstance_l.hThread = CreateThread(NULL, 0, edrvWorkerThread, &edrvInstance_l, 0, &threadId);
    if (edrvInstance_l.hThread == NULL)
        return kErrorEdrvInit;

    return kErrorOk;
}
//------------------------------------------------------------------------------
tOplkError edrv_init(const tEdrvInitParam* pEdrvInitParam_p)
{
    struct sched_param  schedParam;

    // Check parameter validity
    ASSERT(pEdrvInitParam_p != NULL);

    // clear instance structure
    OPLK_MEMSET(&edrvInstance_l, 0, sizeof(edrvInstance_l));

    if (pEdrvInitParam_p->pDevName == NULL)
        return kErrorEdrvInit;

    // save the init data
    edrvInstance_l.initParam = *pEdrvInitParam_p;

    /* if no MAC address was specified read MAC address of used
     * Ethernet interface
     */
    if ((edrvInstance_l.initParam.aMacAddr[0] == 0) &&
        (edrvInstance_l.initParam.aMacAddr[1] == 0) &&
        (edrvInstance_l.initParam.aMacAddr[2] == 0) &&
        (edrvInstance_l.initParam.aMacAddr[3] == 0) &&
        (edrvInstance_l.initParam.aMacAddr[4] == 0) &&
        (edrvInstance_l.initParam.aMacAddr[5] == 0))
    {   // read MAC address from controller
        getMacAdrs(edrvInstance_l.initParam.pDevName,
                   edrvInstance_l.initParam.aMacAddr);
    }

    // Set up and activate the pcap live capture handle
    edrvInstance_l.pPcap = startPcap();
    if (edrvInstance_l.pPcap == NULL)
    {
        return kErrorEdrvInit;
    }

    if (pcap_setdirection(edrvInstance_l.pPcap, PCAP_D_OUT) < 0)
    {
        DEBUG_LVL_ERROR_TRACE("%s() couldn't set PCAP direction\n", __func__);
        return kErrorEdrvInit;
    }

    if (pthread_mutex_init(&edrvInstance_l.mutex, NULL) != 0)
    {
        DEBUG_LVL_ERROR_TRACE("%s() couldn't init mutex\n", __func__);
        return kErrorEdrvInit;
    }

    if (sem_init(&edrvInstance_l.syncSem, 0, 0) != 0)
    {
        DEBUG_LVL_ERROR_TRACE("%s() couldn't init semaphore\n", __func__);
        return kErrorEdrvInit;
    }

    if (pthread_create(&edrvInstance_l.hThread, NULL,
                       workerThread,  &edrvInstance_l) != 0)
    {
        DEBUG_LVL_ERROR_TRACE("%s() Couldn't create worker thread!\n", __func__);
        return kErrorEdrvInit;
    }

    schedParam.sched_priority = CONFIG_THREAD_PRIORITY_MEDIUM;
    if (pthread_setschedparam(edrvInstance_l.hThread, SCHED_FIFO, &schedParam) != 0)
    {
        DEBUG_LVL_ERROR_TRACE("%s() couldn't set thread scheduling parameters!\n", __func__);
    }

#if (defined(__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 12))
    pthread_setname_np(edrvInstance_l.hThread, "oplk-edrvpcap");
#endif

    /* wait until thread is started */
    sem_wait(&edrvInstance_l.syncSem);

    return kErrorOk;
}