⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 netbios.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Copyright (c) 2003 Juan Lang
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#include "config.h"
#include "wine/debug.h"
#include "nbcmdqueue.h"
#include "netbios.h"

WINE_DEFAULT_DEBUG_CHANNEL(netbios);

/* This file provides a NetBIOS emulator that implements the NetBIOS interface,
 * including thread safety and asynchronous call support.  The protocol
 * implementation is separate, with blocking (synchronous) functions.
 */

#define ADAPTERS_INCR 8
#define DEFAULT_NUM_SESSIONS 16

typedef struct _NetBIOSTransportTableEntry
{
    ULONG            id;
    NetBIOSTransport transport;
} NetBIOSTransportTableEntry;

typedef struct _NetBIOSSession
{
    BOOL  inUse;
    UCHAR state;
    UCHAR local_name[NCBNAMSZ];
    UCHAR remote_name[NCBNAMSZ];
    void *data;
} NetBIOSSession;

/* This struct needs a little explanation, unfortunately.  enabled is only
 * used by nbInternalEnum (see).  If transport_id is not 0 and transport
 * is not NULL, the adapter is considered valid.  (transport is a pointer to
 * an entry in a NetBIOSTransportTableEntry.)  data has data for the callers of
 * NetBIOSEnumAdapters to be able to see.  The lana is repeated there, even
 * though I don't use it internally--it's for transports to use reenabling
 * adapters using NetBIOSEnableAdapter.
 */
typedef struct _NetBIOSAdapter
{
    BOOL               enabled;
    BOOL               shuttingDown;
    LONG               resetting;
    ULONG              transport_id;
    NetBIOSTransport  *transport;
    NetBIOSAdapterImpl impl;
    struct NBCmdQueue *cmdQueue;
    CRITICAL_SECTION   cs;
    DWORD              sessionsLen;
    NetBIOSSession    *sessions;
} NetBIOSAdapter;

typedef struct _NetBIOSAdapterTable {
    CRITICAL_SECTION cs;
    BOOL             enumerated;
    BOOL             enumerating;
    UCHAR            tableSize;
    NetBIOSAdapter  *table;
} NetBIOSAdapterTable;

/* Just enough space for NBT right now */
static NetBIOSTransportTableEntry gTransports[1];
static UCHAR gNumTransports = 0;
static NetBIOSAdapterTable gNBTable;

static UCHAR nbResizeAdapterTable(UCHAR newSize)
{
    UCHAR ret;

    if (gNBTable.table)
        gNBTable.table = HeapReAlloc(GetProcessHeap(),
         HEAP_ZERO_MEMORY, gNBTable.table,
         newSize * sizeof(NetBIOSAdapter));
    else
        gNBTable.table = HeapAlloc(GetProcessHeap(),
         HEAP_ZERO_MEMORY, newSize * sizeof(NetBIOSAdapter));
    if (gNBTable.table)
    {
        gNBTable.tableSize = newSize;
        ret = NRC_GOODRET;
    }
    else
        ret = NRC_OSRESNOTAV;
    return ret;
}

void NetBIOSInit(void)
{
    memset(&gNBTable, 0, sizeof(gNBTable));
    InitializeCriticalSection(&gNBTable.cs);
}

void NetBIOSShutdown(void)
{
    UCHAR i;

    EnterCriticalSection(&gNBTable.cs);
    for (i = 0; i < gNBTable.tableSize; i++)
    {
        if (gNBTable.table[i].transport &&
         gNBTable.table[i].transport->cleanupAdapter)
            gNBTable.table[i].transport->cleanupAdapter(
             gNBTable.table[i].impl.data);
    }
    for (i = 0; i < gNumTransports; i++)
        if (gTransports[i].transport.cleanup)
            gTransports[i].transport.cleanup();
    LeaveCriticalSection(&gNBTable.cs);
    DeleteCriticalSection(&gNBTable.cs);
    HeapFree(GetProcessHeap(), 0, gNBTable.table);
}

BOOL NetBIOSRegisterTransport(ULONG id, NetBIOSTransport *transport)
{
    BOOL ret;

    TRACE(": transport 0x%08lx, p %p\n", id, transport);
    if (!transport)
        ret = FALSE;
    else if (gNumTransports >= sizeof(gTransports) / sizeof(gTransports[0]))
    {
        FIXME("You tried to add %d transports, but I only have space for %d\n",
         gNumTransports + 1, sizeof(gTransports) / sizeof(gTransports[0]));
        ret = FALSE;
    }
    else
    {
        UCHAR i;

        ret = FALSE;
        for (i = 0; !ret && i < gNumTransports; i++)
        {
            if (gTransports[i].id == id)
            {
                WARN("Replacing NetBIOS transport ID %ld\n", id);
                memcpy(&gTransports[i].transport, transport,
                 sizeof(NetBIOSTransport));
                ret = TRUE;
            }
        }
        if (!ret)
        {
            gTransports[gNumTransports].id = id;
            memcpy(&gTransports[gNumTransports].transport, transport,
             sizeof(NetBIOSTransport));
            gNumTransports++;
            ret = TRUE;
        }
    }
    TRACE("returning %d\n", ret);
    return ret;
}

/* In this, I acquire the table lock to make sure no one else is modifying it.
 * This is _probably_ overkill since it should only be called during the
 * context of a NetBIOSEnum call, but just to be safe..
 */
BOOL NetBIOSRegisterAdapter(ULONG transport, DWORD ifIndex, void *data)
{
    BOOL ret;
    UCHAR i;

    TRACE(": transport 0x%08lx, ifIndex 0x%08lx, data %p\n", transport, ifIndex,
     data);
    for (i = 0; i < gNumTransports && gTransports[i].id != transport; i++)
        ;
    if (gTransports[i].id == transport)
    {
        NetBIOSTransport *transportPtr = &gTransports[i].transport;

        TRACE(": found transport %p for id 0x%08lx\n", transportPtr, transport);

        EnterCriticalSection(&gNBTable.cs);
        ret = FALSE;
        for (i = 0; i < gNBTable.tableSize &&
         gNBTable.table[i].transport != 0; i++)
            ;
        if (i == gNBTable.tableSize && gNBTable.tableSize < MAX_LANA + 1)
        {
            UCHAR newSize;

            if (gNBTable.tableSize < (MAX_LANA + 1) - ADAPTERS_INCR)
                newSize = gNBTable.tableSize + ADAPTERS_INCR;
            else
                newSize = MAX_LANA + 1;
            nbResizeAdapterTable(newSize);
        }
        if (i < gNBTable.tableSize && gNBTable.table[i].transport == 0)
        {
            TRACE(": registering as LANA %d\n", i);
            gNBTable.table[i].transport_id = transport;
            gNBTable.table[i].transport = transportPtr;
            gNBTable.table[i].impl.lana = i;
            gNBTable.table[i].impl.ifIndex = ifIndex;
            gNBTable.table[i].impl.data = data;
            gNBTable.table[i].cmdQueue = NBCmdQueueCreate(GetProcessHeap());
            InitializeCriticalSection(&gNBTable.table[i].cs);
            gNBTable.table[i].enabled = TRUE;
            ret = TRUE;
        }
        LeaveCriticalSection(&gNBTable.cs);
    }
    else
        ret = FALSE;
    TRACE("returning %d\n", ret);
    return ret;
}

/* In this, I acquire the table lock to make sure no one else is modifying it.
 * This is _probably_ overkill since it should only be called during the
 * context of a NetBIOSEnum call, but just to be safe..
 */
void NetBIOSEnableAdapter(UCHAR lana)
{
    TRACE(": %d\n", lana);
    if (lana < gNBTable.tableSize)
    {
        EnterCriticalSection(&gNBTable.cs);
        if (gNBTable.table[lana].transport != 0)
            gNBTable.table[lana].enabled = TRUE;
        LeaveCriticalSection(&gNBTable.cs);
    }
}

static void nbShutdownAdapter(NetBIOSAdapter *adapter)
{
    if (adapter)
    {
        adapter->shuttingDown = TRUE;
        NBCmdQueueCancelAll(adapter->cmdQueue);
        if (adapter->transport->cleanupAdapter)
            adapter->transport->cleanupAdapter(adapter->impl.data);
        NBCmdQueueDestroy(adapter->cmdQueue);
        DeleteCriticalSection(&adapter->cs);
        memset(adapter, 0, sizeof(NetBIOSAdapter));
    }
}

static void nbInternalEnum(void)
{
    UCHAR i;

    EnterCriticalSection(&gNBTable.cs);
    TRACE("before mark\n");
    /* mark: */
    for (i = 0; i < gNBTable.tableSize; i++)
        if (gNBTable.table[i].enabled && gNBTable.table[i].transport != 0)
            gNBTable.table[i].enabled = FALSE;

    TRACE("marked, before store, %d transports\n", gNumTransports);
    /* store adapters: */
    for (i = 0; i < gNumTransports; i++)
        if (gTransports[i].transport.enumerate)
            gTransports[i].transport.enumerate();

    TRACE("before sweep\n");
    /* sweep: */
    for (i = 0; i < gNBTable.tableSize; i++)
        if (!gNBTable.table[i].enabled && gNBTable.table[i].transport != 0)
            nbShutdownAdapter(&gNBTable.table[i]);
    gNBTable.enumerated = TRUE;
    LeaveCriticalSection(&gNBTable.cs);
}

UCHAR NetBIOSNumAdapters(void)
{
    UCHAR ret, i;

    if (!gNBTable.enumerated)
        nbInternalEnum();
    for (i = 0, ret = 0; i < gNBTable.tableSize; i++)
        if (gNBTable.table[i].transport != 0)
            ret++;
    return ret;
}

void NetBIOSEnumAdapters(ULONG transport, NetBIOSEnumAdaptersCallback cb,
 void *closure)
{
    TRACE("transport 0x%08lx, callback %p, closure %p\n", transport, cb,
     closure);
    if (cb)
    {
        BOOL enumAll = memcmp(&transport, ALL_TRANSPORTS, sizeof(ULONG)) == 0;
        UCHAR i, numLANAs = 0;

        EnterCriticalSection(&gNBTable.cs);
        if (!gNBTable.enumerating)
        {
            gNBTable.enumerating = TRUE;
            nbInternalEnum();
            gNBTable.enumerating = FALSE;
        }
        for (i = 0; i < gNBTable.tableSize; i++)
            if (enumAll || gNBTable.table[i].transport_id == transport)
                numLANAs++;
        if (numLANAs > 0)
        {
            UCHAR lanaIndex = 0;

            for (i = 0; i < gNBTable.tableSize; i++)
                if (gNBTable.table[i].transport_id != 0 &&
                 (enumAll || gNBTable.table[i].transport_id == transport))
                    cb(numLANAs, lanaIndex++, gNBTable.table[i].transport_id,
                     &gNBTable.table[i].impl, closure);
        }
        LeaveCriticalSection(&gNBTable.cs);
    }
}

static NetBIOSAdapter *nbGetAdapter(UCHAR lana)
{
    NetBIOSAdapter *ret = NULL;

    TRACE(": lana %d, num allocated adapters %d\n", lana, gNBTable.tableSize);
    if (lana < gNBTable.tableSize && gNBTable.table[lana].transport_id != 0
     && gNBTable.table[lana].transport)
        ret = &gNBTable.table[lana];
    TRACE("returning %p\n", ret);
    return ret;
}

static UCHAR nbEnum(PNCB ncb)
{
    PLANA_ENUM lanas = (PLANA_ENUM)ncb->ncb_buffer;
    UCHAR i, ret;

    TRACE(": ncb %p\n", ncb);

    if (!lanas)
        ret = NRC_BUFLEN;
    else if (ncb->ncb_length < sizeof(LANA_ENUM))
        ret = NRC_BUFLEN;
    else
    {
        nbInternalEnum();
        lanas->length = 0;
        for (i = 0; i < gNBTable.tableSize; i++)
            if (gNBTable.table[i].transport)
            {
                lanas->length++;
                lanas->lana[i] = i;
            }
        ret = NRC_GOODRET;
    }
    TRACE("returning 0x%02x\n", ret);
    return ret;
}

static UCHAR nbInternalHangup(NetBIOSAdapter *adapter, NetBIOSSession *session);

static UCHAR nbCancel(NetBIOSAdapter *adapter, PNCB ncb)
{
    UCHAR ret;

    TRACE(": adapter %p, ncb %p\n", adapter, ncb);

    if (!adapter) return NRC_BRIDGE;
    if (!ncb) return NRC_INVADDRESS;

    switch (ncb->ncb_command & 0x7f)
    {
        case NCBCANCEL:
        case NCBADDNAME:
        case NCBADDGRNAME:
        case NCBDELNAME:
        case NCBRESET:
        case NCBSSTAT:
            ret = NRC_CANCEL;
            break;

        /* NCBCALL, NCBCHAINSEND/NCBSEND, NCBHANGUP all close the associated
         * session if cancelled */
        case NCBCALL:
        case NCBSEND:
        case NCBCHAINSEND:
        case NCBSENDNA:
        case NCBCHAINSENDNA:
        case NCBHANGUP:
        {
            if (ncb->ncb_lsn >= adapter->sessionsLen)
                ret = NRC_SNUMOUT;
            else if (!adapter->sessions[ncb->ncb_lsn].inUse)
                ret = NRC_SNUMOUT;
            else
            {
                ret = NBCmdQueueCancel(adapter->cmdQueue, ncb);
                if (ret == NRC_CMDCAN || ret == NRC_CANOCCR)
                    nbInternalHangup(adapter, &adapter->sessions[ncb->ncb_lsn]);
            }
            break;
        }

        default:
            ret = NBCmdQueueCancel(adapter->cmdQueue, ncb);
    }
    TRACE("returning 0x%02x\n", ret);
    return ret;
}

/* Resizes adapter to contain space for at least sessionsLen sessions.
 * If allocating more space for sessions, sets the adapter's sessionsLen to
 * sessionsLen.  If the adapter's sessionsLen was already at least sessionsLen,
 * does nothing.  Does not modify existing sessions.  Assumes the adapter is
 * locked.
 * Returns NRC_GOODRET on success, and something else on failure.
 */
static UCHAR nbResizeAdapter(NetBIOSAdapter *adapter, UCHAR sessionsLen)
{
    UCHAR ret = NRC_GOODRET;

    if (adapter && adapter->sessionsLen < sessionsLen)
    {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -