📄 nbt.c
字号:
adapter->nameQueryXID++;
astat->name_count = 0;
queryData.gotResponse = FALSE;
queryData.astat = astat;
queryData.astatLen = ncb->ncb_length;
for (queries = 0; !queryData.gotResponse &&
queries < gWINSQueries; queries++)
{
if (!NCB_CANCELLED(ncb))
{
int r = NetBTSendNameQuery(fd, ncb->ncb_callname,
adapter->nameQueryXID, NBNS_TYPE_NBSTAT,
cacheEntry->addresses[0], FALSE);
if (r == 0)
ret = NetBTWaitForNameResponse(adapter, fd,
GetTickCount() + gWINSQueryTimeout,
NetBTNodeStatusAnswerCallback, &queryData);
else
ret = NRC_SYSTEM;
}
else
ret = NRC_CMDCAN;
}
closesocket(fd);
}
}
else
ret = NRC_CMDTMO;
}
else if (ret == NRC_CMDCAN)
; /* do nothing, we were cancelled */
else
ret = NRC_CMDTMO;
TRACE("returning 0x%02x\n", ret);
return ret;
}
static UCHAR NetBTAstat(void *adapt, PNCB ncb)
{
NetBTAdapter *adapter = (NetBTAdapter *)adapt;
UCHAR ret;
TRACE("adapt %p, NCB %p\n", adapt, ncb);
if (!adapter) return NRC_ENVNOTDEF;
if (!ncb) return NRC_INVADDRESS;
if (!ncb->ncb_buffer) return NRC_BADDR;
if (ncb->ncb_length < sizeof(ADAPTER_STATUS)) return NRC_BUFLEN;
if (ncb->ncb_callname[0] == '*')
{
DWORD physAddrLen;
MIB_IFROW ifRow;
PADAPTER_STATUS astat = (PADAPTER_STATUS)ncb->ncb_buffer;
memset(astat, 0, sizeof(ADAPTER_STATUS));
astat->rev_major = 3;
ifRow.dwIndex = adapter->ipr.dwIndex;
if (GetIfEntry(&ifRow) != NO_ERROR)
ret = NRC_BRIDGE;
else
{
physAddrLen = min(ifRow.dwPhysAddrLen, 6);
if (physAddrLen > 0)
memcpy(astat->adapter_address, ifRow.bPhysAddr, physAddrLen);
/* doubt anyone cares, but why not.. */
if (ifRow.dwType == MIB_IF_TYPE_TOKENRING)
astat->adapter_type = 0xff;
else
astat->adapter_type = 0xfe; /* for Ethernet */
astat->max_sess_pkt_size = 0xffff;
astat->xmit_success = adapter->xmit_success;
astat->recv_success = adapter->recv_success;
}
ret = NRC_GOODRET;
}
else
ret = NetBTAstatRemote(adapter, ncb);
TRACE("returning 0x%02x\n", ret);
return ret;
}
static UCHAR NetBTFindName(void *adapt, PNCB ncb)
{
NetBTAdapter *adapter = (NetBTAdapter *)adapt;
UCHAR ret;
const NBNameCacheEntry *cacheEntry = NULL;
PFIND_NAME_HEADER foundName;
TRACE("adapt %p, NCB %p\n", adapt, ncb);
if (!adapter) return NRC_ENVNOTDEF;
if (!ncb) return NRC_INVADDRESS;
if (!ncb->ncb_buffer) return NRC_BADDR;
if (ncb->ncb_length < sizeof(FIND_NAME_HEADER)) return NRC_BUFLEN;
foundName = (PFIND_NAME_HEADER)ncb->ncb_buffer;
memset(foundName, 0, sizeof(FIND_NAME_HEADER));
ret = NetBTInternalFindName(adapter, ncb, &cacheEntry);
if (ret == NRC_GOODRET)
{
if (cacheEntry)
{
DWORD spaceFor = min((ncb->ncb_length - sizeof(FIND_NAME_HEADER)) /
sizeof(FIND_NAME_BUFFER), cacheEntry->numAddresses);
DWORD ndx;
for (ndx = 0; ndx < spaceFor; ndx++)
{
PFIND_NAME_BUFFER findNameBuffer;
findNameBuffer =
(PFIND_NAME_BUFFER)((PUCHAR)foundName +
sizeof(FIND_NAME_HEADER) + foundName->node_count *
sizeof(FIND_NAME_BUFFER));
memset(findNameBuffer->destination_addr, 0, 2);
memcpy(findNameBuffer->destination_addr + 2,
&adapter->ipr.dwAddr, sizeof(DWORD));
memset(findNameBuffer->source_addr, 0, 2);
memcpy(findNameBuffer->source_addr + 2,
&cacheEntry->addresses[ndx], sizeof(DWORD));
foundName->node_count++;
}
if (spaceFor < cacheEntry->numAddresses)
ret = NRC_BUFLEN;
}
else
ret = NRC_CMDTMO;
}
TRACE("returning 0x%02x\n", ret);
return ret;
}
static UCHAR NetBTSessionReq(SOCKET fd, const UCHAR *calledName,
const UCHAR *callingName)
{
UCHAR buffer[NBSS_HDRSIZE + MAX_DOMAIN_NAME_LEN * 2], ret;
int r;
unsigned int len = 0;
DWORD bytesSent, bytesReceived, recvFlags = 0;
WSABUF wsaBuf;
buffer[0] = NBSS_REQ;
buffer[1] = 0;
len += NetBTNameEncode(calledName, &buffer[NBSS_HDRSIZE]);
len += NetBTNameEncode(callingName, &buffer[NBSS_HDRSIZE + len]);
NBR_ADDWORD(&buffer[2], len);
wsaBuf.len = len + NBSS_HDRSIZE;
wsaBuf.buf = (char*)buffer;
r = WSASend(fd, &wsaBuf, 1, &bytesSent, 0, NULL, NULL);
if(r < 0 || bytesSent < len + NBSS_HDRSIZE)
{
ERR("send failed\n");
return NRC_SABORT;
}
/* I've already set the recv timeout on this socket (if it supports it), so
* just block. Hopefully we'll always receive the session acknowledgement
* within one timeout.
*/
wsaBuf.len = NBSS_HDRSIZE + 1;
r = WSARecv(fd, &wsaBuf, 1, &bytesReceived, &recvFlags, NULL, NULL);
if (r < 0 || bytesReceived < NBSS_HDRSIZE)
ret = NRC_SABORT;
else if (buffer[0] == NBSS_NACK)
{
if (r == NBSS_HDRSIZE + 1)
{
switch (buffer[NBSS_HDRSIZE])
{
case NBSS_ERR_INSUFFICIENT_RESOURCES:
ret = NRC_REMTFUL;
break;
default:
ret = NRC_NOCALL;
}
}
else
ret = NRC_NOCALL;
}
else if (buffer[0] == NBSS_RETARGET)
{
FIXME("Got a session retarget, can't deal\n");
ret = NRC_NOCALL;
}
else if (buffer[0] == NBSS_ACK)
ret = NRC_GOODRET;
else
ret = NRC_SYSTEM;
TRACE("returning 0x%02x\n", ret);
return ret;
}
static UCHAR NetBTCall(void *adapt, PNCB ncb, void **sess)
{
NetBTAdapter *adapter = (NetBTAdapter *)adapt;
UCHAR ret;
const NBNameCacheEntry *cacheEntry = NULL;
TRACE("adapt %p, ncb %p\n", adapt, ncb);
if (!adapter) return NRC_ENVNOTDEF;
if (!ncb) return NRC_INVADDRESS;
if (!sess) return NRC_BADDR;
ret = NetBTInternalFindName(adapter, ncb, &cacheEntry);
if (ret == NRC_GOODRET)
{
if (cacheEntry && cacheEntry->numAddresses > 0)
{
SOCKET fd;
fd = WSASocketA(PF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
WSA_FLAG_OVERLAPPED);
if (fd != INVALID_SOCKET)
{
DWORD timeout;
struct sockaddr_in sin;
if (ncb->ncb_rto > 0)
{
timeout = ncb->ncb_rto * 500;
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout,
sizeof(timeout));
}
if (ncb->ncb_rto > 0)
{
timeout = ncb->ncb_sto * 500;
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout,
sizeof(timeout));
}
memset(&sin, 0, sizeof(sin));
memcpy(&sin.sin_addr, &cacheEntry->addresses[0],
sizeof(sin.sin_addr));
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT_NBSS);
/* FIXME: use nonblocking mode for the socket, check the
* cancel flag periodically
*/
if (connect(fd, (struct sockaddr *)&sin, sizeof(sin))
== SOCKET_ERROR)
ret = NRC_CMDTMO;
else
{
static const UCHAR fakedCalledName[] = "*SMBSERVER";
const UCHAR *calledParty = cacheEntry->nbname[0] == '*'
? fakedCalledName : cacheEntry->nbname;
ret = NetBTSessionReq(fd, calledParty, ncb->ncb_name);
if (ret != NRC_GOODRET && calledParty[0] == '*')
{
FIXME("NBT session to \"*SMBSERVER\" refused,\n");
FIXME("should try finding name using ASTAT\n");
}
}
if (ret != NRC_GOODRET)
closesocket(fd);
else
{
NetBTSession *session = HeapAlloc(
GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NetBTSession));
if (session)
{
session->fd = fd;
InitializeCriticalSection(&session->cs);
session->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": NetBTSession.cs");
*sess = session;
}
else
{
ret = NRC_OSRESNOTAV;
closesocket(fd);
}
}
}
else
ret = NRC_OSRESNOTAV;
}
else
ret = NRC_NAMERR;
}
TRACE("returning 0x%02x\n", ret);
return ret;
}
/* Notice that I don't protect against multiple thread access to NetBTSend.
* This is because I don't update any data in the adapter, and I only make a
* single call to WSASend, which I assume to act atomically (not interleaving
* data from other threads).
* I don't lock, because I only depend on the fd being valid, and this won't be
* true until a session setup is completed.
*/
static UCHAR NetBTSend(void *adapt, void *sess, PNCB ncb)
{
NetBTAdapter *adapter = (NetBTAdapter *)adapt;
NetBTSession *session = (NetBTSession *)sess;
UCHAR buffer[NBSS_HDRSIZE], ret;
int r;
WSABUF wsaBufs[2];
DWORD bytesSent;
TRACE("adapt %p, session %p, NCB %p\n", adapt, session, ncb);
if (!adapter) return NRC_ENVNOTDEF;
if (!ncb) return NRC_INVADDRESS;
if (!ncb->ncb_buffer) return NRC_BADDR;
if (!session) return NRC_SNUMOUT;
if (session->fd == INVALID_SOCKET) return NRC_SNUMOUT;
buffer[0] = NBSS_MSG;
buffer[1] = 0;
NBR_ADDWORD(&buffer[2], ncb->ncb_length);
wsaBufs[0].len = NBSS_HDRSIZE;
wsaBufs[0].buf = (char*)buffer;
wsaBufs[1].len = ncb->ncb_length;
wsaBufs[1].buf = (char*)ncb->ncb_buffer;
r = WSASend(session->fd, wsaBufs, sizeof(wsaBufs) / sizeof(wsaBufs[0]),
&bytesSent, 0, NULL, NULL);
if (r == SOCKET_ERROR)
{
NetBIOSHangupSession(ncb);
ret = NRC_SABORT;
}
else if (bytesSent < NBSS_HDRSIZE + ncb->ncb_length)
{
FIXME("Only sent %d bytes (of %d), hanging up session\n", bytesSent,
NBSS_HDRSIZE + ncb->ncb_length);
NetBIOSHangupSession(ncb);
ret = NRC_SABORT;
}
else
{
ret = NRC_GOODRET;
adapter->xmit_success++;
}
TRACE("returning 0x%02x\n", ret);
return ret;
}
static UCHAR NetBTRecv(void *adapt, void *sess, PNCB ncb)
{
NetBTAdapter *adapter = (NetBTAdapter *)adapt;
NetBTSession *session = (NetBTSession *)sess;
UCHAR buffer[NBSS_HDRSIZE], ret;
int r;
WSABUF wsaBufs[2];
DWORD bufferCount, bytesReceived, flags;
TRACE("adapt %p, session %p, NCB %p\n", adapt, session, ncb);
if (!adapter) return NRC_ENVNOTDEF;
if (!ncb) return NRC_BADDR;
if (!ncb->ncb_buffer) return NRC_BADDR;
if (!session) return NRC_SNUMOUT;
if (session->fd == INVALID_SOCKET) return NRC_SNUMOUT;
EnterCriticalSection(&session->cs);
bufferCount = 0;
if (session->bytesPending == 0)
{
bufferCount++;
wsaBufs[0].len = NBSS_HDRSIZE;
wsaBufs[0].buf = (char*)buffer;
}
wsaBufs[bufferCount].len = ncb->ncb_length;
wsaBufs[bufferCount].buf = (char*)ncb->ncb_buffer;
bufferCount++;
flags = 0;
/* FIXME: should poll a bit so I can check the cancel flag */
r = WSARecv(session->fd, wsaBufs, bufferCount, &bytesReceived, &flags,
NULL, NULL);
if (r == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK)
{
LeaveCriticalSection(&session->cs);
ERR("Receive error, WSAGetLastError() returns %d\n", WSAGetLastError());
NetBIOSHangupSession(ncb);
ret = NRC_SABORT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -