1 /* Copyright (c) 2003 Juan Lang
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 #include "wine/debug.h"
19 #include "nbcmdqueue.h"
22 WINE_DEFAULT_DEBUG_CHANNEL(netbios
);
24 /* This file provides a NetBIOS emulator that implements the NetBIOS interface,
25 * including thread safety and asynchronous call support. The protocol
26 * implementation is separate, with blocking (synchronous) functions.
29 #define ADAPTERS_INCR 8
30 #define DEFAULT_NUM_SESSIONS 16
32 typedef struct _NetBIOSTransportTableEntry
35 NetBIOSTransport transport
;
36 } NetBIOSTransportTableEntry
;
38 typedef struct _NetBIOSSession
42 UCHAR local_name
[NCBNAMSZ
];
43 UCHAR remote_name
[NCBNAMSZ
];
47 /* This struct needs a little explanation, unfortunately. enabled is only
48 * used by nbInternalEnum (see). If transport_id is not 0 and transport
49 * is not NULL, the adapter is considered valid. (transport is a pointer to
50 * an entry in a NetBIOSTransportTableEntry.) data has data for the callers of
51 * NetBIOSEnumAdapters to be able to see. The lana is repeated there, even
52 * though I don't use it internally--it's for transports to use re-enabling
53 * adapters using NetBIOSEnableAdapter.
55 typedef struct _NetBIOSAdapter
61 NetBIOSTransport
*transport
;
62 NetBIOSAdapterImpl impl
;
63 struct NBCmdQueue
*cmdQueue
;
66 NetBIOSSession
*sessions
;
69 typedef struct _NetBIOSAdapterTable
{
74 NetBIOSAdapter
*table
;
75 } NetBIOSAdapterTable
;
77 /* Just enough space for NBT right now */
78 static NetBIOSTransportTableEntry gTransports
[1];
79 static UCHAR gNumTransports
= 0;
80 static NetBIOSAdapterTable gNBTable
;
82 static UCHAR
nbResizeAdapterTable(UCHAR newSize
)
87 gNBTable
.table
= HeapReAlloc(GetProcessHeap(),
88 HEAP_ZERO_MEMORY
, gNBTable
.table
,
89 newSize
* sizeof(NetBIOSAdapter
));
91 gNBTable
.table
= HeapAlloc(GetProcessHeap(),
92 HEAP_ZERO_MEMORY
, newSize
* sizeof(NetBIOSAdapter
));
95 gNBTable
.tableSize
= newSize
;
103 void NetBIOSInit(void)
105 memset(&gNBTable
, 0, sizeof(gNBTable
));
106 InitializeCriticalSection(&gNBTable
.cs
);
107 gNBTable
.cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": NetBIOSAdapterTable.cs");
110 void NetBIOSShutdown(void)
114 EnterCriticalSection(&gNBTable
.cs
);
115 for (i
= 0; i
< gNBTable
.tableSize
; i
++)
117 if (gNBTable
.table
[i
].transport
&&
118 gNBTable
.table
[i
].transport
->cleanupAdapter
)
119 gNBTable
.table
[i
].transport
->cleanupAdapter(
120 gNBTable
.table
[i
].impl
.data
);
122 for (i
= 0; i
< gNumTransports
; i
++)
123 if (gTransports
[i
].transport
.cleanup
)
124 gTransports
[i
].transport
.cleanup();
125 LeaveCriticalSection(&gNBTable
.cs
);
126 gNBTable
.cs
.DebugInfo
->Spare
[0] = 0;
127 DeleteCriticalSection(&gNBTable
.cs
);
128 HeapFree(GetProcessHeap(), 0, gNBTable
.table
);
131 BOOL
NetBIOSRegisterTransport(ULONG id
, NetBIOSTransport
*transport
)
135 TRACE(": transport 0x%08x, p %p\n", id
, transport
);
138 else if (gNumTransports
>= sizeof(gTransports
) / sizeof(gTransports
[0]))
140 FIXME("Too many transports %d\n", gNumTransports
+ 1);
148 for (i
= 0; !ret
&& i
< gNumTransports
; i
++)
150 if (gTransports
[i
].id
== id
)
152 WARN("Replacing NetBIOS transport ID %d\n", id
);
153 memcpy(&gTransports
[i
].transport
, transport
,
154 sizeof(NetBIOSTransport
));
160 gTransports
[gNumTransports
].id
= id
;
161 memcpy(&gTransports
[gNumTransports
].transport
, transport
,
162 sizeof(NetBIOSTransport
));
167 TRACE("returning %d\n", ret
);
171 /* In this, I acquire the table lock to make sure no one else is modifying it.
172 * This is _probably_ overkill since it should only be called during the
173 * context of a NetBIOSEnum call, but just to be safe..
175 BOOL
NetBIOSRegisterAdapter(ULONG transport
, DWORD ifIndex
, void *data
)
180 TRACE(": transport 0x%08x, ifIndex 0x%08x, data %p\n", transport
, ifIndex
,
182 for (i
= 0; i
< gNumTransports
&& gTransports
[i
].id
!= transport
; i
++)
184 if ((i
< gNumTransports
) && gTransports
[i
].id
== transport
)
186 NetBIOSTransport
*transportPtr
= &gTransports
[i
].transport
;
188 TRACE(": found transport %p for id 0x%08x\n", transportPtr
, transport
);
190 EnterCriticalSection(&gNBTable
.cs
);
192 for (i
= 0; i
< gNBTable
.tableSize
&&
193 gNBTable
.table
[i
].transport
!= 0; i
++)
195 if (i
== gNBTable
.tableSize
&& gNBTable
.tableSize
< MAX_LANA
+ 1)
199 if (gNBTable
.tableSize
< (MAX_LANA
+ 1) - ADAPTERS_INCR
)
200 newSize
= gNBTable
.tableSize
+ ADAPTERS_INCR
;
202 newSize
= MAX_LANA
+ 1;
203 nbResizeAdapterTable(newSize
);
205 if (i
< gNBTable
.tableSize
&& gNBTable
.table
[i
].transport
== 0)
207 TRACE(": registering as LANA %d\n", i
);
208 gNBTable
.table
[i
].transport_id
= transport
;
209 gNBTable
.table
[i
].transport
= transportPtr
;
210 gNBTable
.table
[i
].impl
.lana
= i
;
211 gNBTable
.table
[i
].impl
.ifIndex
= ifIndex
;
212 gNBTable
.table
[i
].impl
.data
= data
;
213 gNBTable
.table
[i
].cmdQueue
= NBCmdQueueCreate(GetProcessHeap());
214 InitializeCriticalSection(&gNBTable
.table
[i
].cs
);
215 gNBTable
.table
[i
].cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": NetBIOSAdapterTable.NetBIOSAdapter.cs");
216 gNBTable
.table
[i
].enabled
= TRUE
;
219 LeaveCriticalSection(&gNBTable
.cs
);
223 TRACE("returning %d\n", ret
);
227 /* In this, I acquire the table lock to make sure no one else is modifying it.
228 * This is _probably_ overkill since it should only be called during the
229 * context of a NetBIOSEnum call, but just to be safe..
231 void NetBIOSEnableAdapter(UCHAR lana
)
233 TRACE(": %d\n", lana
);
234 if (lana
< gNBTable
.tableSize
)
236 EnterCriticalSection(&gNBTable
.cs
);
237 if (gNBTable
.table
[lana
].transport
!= 0)
238 gNBTable
.table
[lana
].enabled
= TRUE
;
239 LeaveCriticalSection(&gNBTable
.cs
);
243 static void nbShutdownAdapter(NetBIOSAdapter
*adapter
)
247 adapter
->shuttingDown
= TRUE
;
248 NBCmdQueueCancelAll(adapter
->cmdQueue
);
249 if (adapter
->transport
->cleanupAdapter
)
250 adapter
->transport
->cleanupAdapter(adapter
->impl
.data
);
251 NBCmdQueueDestroy(adapter
->cmdQueue
);
252 adapter
->cs
.DebugInfo
->Spare
[0] = 0;
253 DeleteCriticalSection(&adapter
->cs
);
254 memset(adapter
, 0, sizeof(NetBIOSAdapter
));
258 static void nbInternalEnum(void)
262 EnterCriticalSection(&gNBTable
.cs
);
263 TRACE("before mark\n");
265 for (i
= 0; i
< gNBTable
.tableSize
; i
++)
266 if (gNBTable
.table
[i
].enabled
&& gNBTable
.table
[i
].transport
!= 0)
267 gNBTable
.table
[i
].enabled
= FALSE
;
269 TRACE("marked, before store, %d transports\n", gNumTransports
);
270 /* store adapters: */
271 for (i
= 0; i
< gNumTransports
; i
++)
272 if (gTransports
[i
].transport
.enumerate
)
273 gTransports
[i
].transport
.enumerate();
275 TRACE("before sweep\n");
277 for (i
= 0; i
< gNBTable
.tableSize
; i
++)
278 if (!gNBTable
.table
[i
].enabled
&& gNBTable
.table
[i
].transport
!= 0)
279 nbShutdownAdapter(&gNBTable
.table
[i
]);
280 gNBTable
.enumerated
= TRUE
;
281 LeaveCriticalSection(&gNBTable
.cs
);
284 UCHAR
NetBIOSNumAdapters(void)
288 if (!gNBTable
.enumerated
)
290 for (i
= 0, ret
= 0; i
< gNBTable
.tableSize
; i
++)
291 if (gNBTable
.table
[i
].transport
!= 0)
296 void NetBIOSEnumAdapters(ULONG transport
, NetBIOSEnumAdaptersCallback cb
,
299 TRACE("transport 0x%08x, callback %p, closure %p\n", transport
, cb
,
303 BOOL enumAll
= memcmp(&transport
, ALL_TRANSPORTS
, sizeof(ULONG
)) == 0;
304 UCHAR i
, numLANAs
= 0;
306 EnterCriticalSection(&gNBTable
.cs
);
307 if (!gNBTable
.enumerating
)
309 gNBTable
.enumerating
= TRUE
;
311 gNBTable
.enumerating
= FALSE
;
313 for (i
= 0; i
< gNBTable
.tableSize
; i
++)
314 if (enumAll
|| gNBTable
.table
[i
].transport_id
== transport
)
320 for (i
= 0; i
< gNBTable
.tableSize
; i
++)
321 if (gNBTable
.table
[i
].transport_id
!= 0 &&
322 (enumAll
|| gNBTable
.table
[i
].transport_id
== transport
))
323 cb(numLANAs
, lanaIndex
++, gNBTable
.table
[i
].transport_id
,
324 &gNBTable
.table
[i
].impl
, closure
);
326 LeaveCriticalSection(&gNBTable
.cs
);
330 static NetBIOSAdapter
*nbGetAdapter(UCHAR lana
)
332 NetBIOSAdapter
*ret
= NULL
;
334 TRACE(": lana %d, num allocated adapters %d\n", lana
, gNBTable
.tableSize
);
335 if (lana
< gNBTable
.tableSize
&& gNBTable
.table
[lana
].transport_id
!= 0
336 && gNBTable
.table
[lana
].transport
)
337 ret
= &gNBTable
.table
[lana
];
338 TRACE("returning %p\n", ret
);
342 static UCHAR
nbEnum(PNCB ncb
)
344 PLANA_ENUM lanas
= (PLANA_ENUM
)ncb
->ncb_buffer
;
347 TRACE(": ncb %p\n", ncb
);
351 else if (ncb
->ncb_length
< sizeof(LANA_ENUM
))
357 for (i
= 0; i
< gNBTable
.tableSize
; i
++)
358 if (gNBTable
.table
[i
].transport
)
365 TRACE("returning 0x%02x\n", ret
);
369 static UCHAR
nbInternalHangup(NetBIOSAdapter
*adapter
, NetBIOSSession
*session
);
371 static UCHAR
nbCancel(NetBIOSAdapter
*adapter
, PNCB ncb
)
375 TRACE(": adapter %p, ncb %p\n", adapter
, ncb
);
377 if (!adapter
) return NRC_BRIDGE
;
378 if (!ncb
) return NRC_INVADDRESS
;
380 switch (ncb
->ncb_command
& 0x7f)
391 /* NCBCALL, NCBCHAINSEND/NCBSEND, NCBHANGUP all close the associated
392 * session if cancelled */
400 if (ncb
->ncb_lsn
>= adapter
->sessionsLen
)
402 else if (!adapter
->sessions
[ncb
->ncb_lsn
].inUse
)
406 ret
= NBCmdQueueCancel(adapter
->cmdQueue
, ncb
);
407 if (ret
== NRC_CMDCAN
|| ret
== NRC_CANOCCR
)
408 nbInternalHangup(adapter
, &adapter
->sessions
[ncb
->ncb_lsn
]);
414 ret
= NBCmdQueueCancel(adapter
->cmdQueue
, ncb
);
416 TRACE("returning 0x%02x\n", ret
);
420 /* Resizes adapter to contain space for at least sessionsLen sessions.
421 * If allocating more space for sessions, sets the adapter's sessionsLen to
422 * sessionsLen. If the adapter's sessionsLen was already at least sessionsLen,
423 * does nothing. Does not modify existing sessions. Assumes the adapter is
425 * Returns NRC_GOODRET on success, and something else on failure.
427 static UCHAR
nbResizeAdapter(NetBIOSAdapter
*adapter
, UCHAR sessionsLen
)
429 UCHAR ret
= NRC_GOODRET
;
431 if (adapter
&& adapter
->sessionsLen
< sessionsLen
)
433 NetBIOSSession
*newSessions
;
435 if (adapter
->sessions
)
436 newSessions
= HeapReAlloc(GetProcessHeap(),
437 HEAP_ZERO_MEMORY
, adapter
->sessions
, sessionsLen
*
438 sizeof(NetBIOSSession
));
440 newSessions
= HeapAlloc(GetProcessHeap(),
441 HEAP_ZERO_MEMORY
, sessionsLen
* sizeof(NetBIOSSession
));
444 adapter
->sessions
= newSessions
;
445 adapter
->sessionsLen
= sessionsLen
;
448 ret
= NRC_OSRESNOTAV
;
453 static UCHAR
nbReset(NetBIOSAdapter
*adapter
, PNCB ncb
)
457 TRACE(": adapter %p, ncb %p\n", adapter
, ncb
);
459 if (!adapter
) return NRC_BRIDGE
;
460 if (!ncb
) return NRC_INVADDRESS
;
462 if (InterlockedIncrement(&adapter
->resetting
) == 1)
466 NBCmdQueueCancelAll(adapter
->cmdQueue
);
468 EnterCriticalSection(&adapter
->cs
);
469 for (i
= 0; i
< adapter
->sessionsLen
; i
++)
470 if (adapter
->sessions
[i
].inUse
)
471 nbInternalHangup(adapter
, &adapter
->sessions
[i
]);
473 resizeTo
= ncb
->ncb_callname
[0] == 0 ? DEFAULT_NUM_SESSIONS
:
474 ncb
->ncb_callname
[0];
475 else if (adapter
->sessionsLen
== 0)
476 resizeTo
= DEFAULT_NUM_SESSIONS
;
480 ret
= nbResizeAdapter(adapter
, resizeTo
);
483 LeaveCriticalSection(&adapter
->cs
);
487 InterlockedDecrement(&adapter
->resetting
);
488 TRACE("returning 0x%02x\n", ret
);
492 static UCHAR
nbSStat(NetBIOSAdapter
*adapter
, PNCB ncb
)
494 UCHAR ret
, i
, spaceFor
;
495 PSESSION_HEADER sstat
;
497 TRACE(": adapter %p, NCB %p\n", adapter
, ncb
);
499 if (!adapter
) return NRC_BADDR
;
500 if (adapter
->sessionsLen
== 0) return NRC_ENVNOTDEF
;
501 if (!ncb
) return NRC_INVADDRESS
;
502 if (!ncb
->ncb_buffer
) return NRC_BADDR
;
503 if (ncb
->ncb_length
< sizeof(SESSION_HEADER
)) return NRC_BUFLEN
;
505 sstat
= (PSESSION_HEADER
)ncb
->ncb_buffer
;
507 memset(sstat
, 0, sizeof(SESSION_HEADER
));
508 spaceFor
= (ncb
->ncb_length
- sizeof(SESSION_HEADER
)) /
509 sizeof(SESSION_BUFFER
);
510 EnterCriticalSection(&adapter
->cs
);
511 for (i
= 0; ret
== NRC_GOODRET
&& i
< adapter
->sessionsLen
; i
++)
513 if (adapter
->sessions
[i
].inUse
&& (ncb
->ncb_name
[0] == '*' ||
514 !memcmp(ncb
->ncb_name
, adapter
->sessions
[i
].local_name
, NCBNAMSZ
)))
516 if (sstat
->num_sess
< spaceFor
)
520 buf
= (PSESSION_BUFFER
)((PUCHAR
)sstat
+ sizeof(SESSION_HEADER
)
521 + sstat
->num_sess
* sizeof(SESSION_BUFFER
));
523 buf
->state
= adapter
->sessions
[i
].state
;
524 memcpy(buf
->local_name
, adapter
->sessions
[i
].local_name
,
526 memcpy(buf
->remote_name
, adapter
->sessions
[i
].remote_name
,
528 buf
->rcvs_outstanding
= buf
->sends_outstanding
= 0;
535 LeaveCriticalSection(&adapter
->cs
);
537 TRACE("returning 0x%02x\n", ret
);
541 static UCHAR
nbCall(NetBIOSAdapter
*adapter
, PNCB ncb
)
545 TRACE(": adapter %p, NCB %p\n", adapter
, ncb
);
547 if (!adapter
) return NRC_BRIDGE
;
548 if (adapter
->sessionsLen
== 0) return NRC_ENVNOTDEF
;
549 if (!adapter
->transport
->call
) return NRC_ILLCMD
;
550 if (!ncb
) return NRC_INVADDRESS
;
552 EnterCriticalSection(&adapter
->cs
);
553 for (i
= 0; i
< adapter
->sessionsLen
&& adapter
->sessions
[i
].inUse
; i
++)
555 if (i
< adapter
->sessionsLen
)
557 adapter
->sessions
[i
].inUse
= TRUE
;
558 adapter
->sessions
[i
].state
= CALL_PENDING
;
559 memcpy(adapter
->sessions
[i
].local_name
, ncb
->ncb_name
, NCBNAMSZ
);
560 memcpy(adapter
->sessions
[i
].remote_name
, ncb
->ncb_callname
, NCBNAMSZ
);
565 LeaveCriticalSection(&adapter
->cs
);
567 if (ret
== NRC_GOODRET
)
569 ret
= adapter
->transport
->call(adapter
->impl
.data
, ncb
,
570 &adapter
->sessions
[i
].data
);
571 if (ret
== NRC_GOODRET
)
574 adapter
->sessions
[i
].state
= SESSION_ESTABLISHED
;
578 adapter
->sessions
[i
].inUse
= FALSE
;
579 adapter
->sessions
[i
].state
= 0;
582 TRACE("returning 0x%02x\n", ret
);
586 static UCHAR
nbSend(NetBIOSAdapter
*adapter
, PNCB ncb
)
589 NetBIOSSession
*session
;
591 if (!adapter
) return NRC_BRIDGE
;
592 if (!adapter
->transport
->send
) return NRC_ILLCMD
;
593 if (!ncb
) return NRC_INVADDRESS
;
594 if (ncb
->ncb_lsn
>= adapter
->sessionsLen
) return NRC_SNUMOUT
;
595 if (!adapter
->sessions
[ncb
->ncb_lsn
].inUse
) return NRC_SNUMOUT
;
596 if (!ncb
->ncb_buffer
) return NRC_BADDR
;
598 session
= &adapter
->sessions
[ncb
->ncb_lsn
];
599 if (session
->state
!= SESSION_ESTABLISHED
)
602 ret
= adapter
->transport
->send(adapter
->impl
.data
, session
->data
, ncb
);
606 static UCHAR
nbRecv(NetBIOSAdapter
*adapter
, PNCB ncb
)
609 NetBIOSSession
*session
;
611 if (!adapter
) return NRC_BRIDGE
;
612 if (!adapter
->transport
->recv
) return NRC_ILLCMD
;
613 if (!ncb
) return NRC_INVADDRESS
;
614 if (ncb
->ncb_lsn
>= adapter
->sessionsLen
) return NRC_SNUMOUT
;
615 if (!adapter
->sessions
[ncb
->ncb_lsn
].inUse
) return NRC_SNUMOUT
;
616 if (!ncb
->ncb_buffer
) return NRC_BADDR
;
618 session
= &adapter
->sessions
[ncb
->ncb_lsn
];
619 if (session
->state
!= SESSION_ESTABLISHED
)
622 ret
= adapter
->transport
->recv(adapter
->impl
.data
, session
->data
, ncb
);
626 static UCHAR
nbInternalHangup(NetBIOSAdapter
*adapter
, NetBIOSSession
*session
)
630 if (!adapter
) return NRC_BRIDGE
;
631 if (!session
) return NRC_SNUMOUT
;
633 if (adapter
->transport
->hangup
)
634 ret
= adapter
->transport
->hangup(adapter
->impl
.data
, session
->data
);
637 EnterCriticalSection(&adapter
->cs
);
638 memset(session
, 0, sizeof(NetBIOSSession
));
639 LeaveCriticalSection(&adapter
->cs
);
643 static UCHAR
nbHangup(NetBIOSAdapter
*adapter
, const NCB
*ncb
)
646 NetBIOSSession
*session
;
648 if (!adapter
) return NRC_BRIDGE
;
649 if (!ncb
) return NRC_INVADDRESS
;
650 if (ncb
->ncb_lsn
>= adapter
->sessionsLen
) return NRC_SNUMOUT
;
651 if (!adapter
->sessions
[ncb
->ncb_lsn
].inUse
) return NRC_SNUMOUT
;
653 session
= &adapter
->sessions
[ncb
->ncb_lsn
];
654 if (session
->state
!= SESSION_ESTABLISHED
)
658 session
->state
= HANGUP_PENDING
;
659 ret
= nbInternalHangup(adapter
, session
);
664 void NetBIOSHangupSession(const NCB
*ncb
)
666 NetBIOSAdapter
*adapter
;
670 adapter
= nbGetAdapter(ncb
->ncb_lana_num
);
673 if (ncb
->ncb_lsn
< adapter
->sessionsLen
&&
674 adapter
->sessions
[ncb
->ncb_lsn
].inUse
)
675 nbHangup(adapter
, ncb
);
679 static UCHAR
nbAStat(NetBIOSAdapter
*adapter
, PNCB ncb
)
683 if (!adapter
) return NRC_BRIDGE
;
684 if (!adapter
->transport
->astat
) return NRC_ILLCMD
;
685 if (!ncb
) return NRC_INVADDRESS
;
686 if (!ncb
->ncb_buffer
) return NRC_BADDR
;
687 if (ncb
->ncb_length
< sizeof(ADAPTER_STATUS
)) return NRC_BUFLEN
;
689 ret
= adapter
->transport
->astat(adapter
->impl
.data
, ncb
);
690 if (ncb
->ncb_callname
[0] == '*')
692 PADAPTER_STATUS astat
= (PADAPTER_STATUS
)ncb
->ncb_buffer
;
694 astat
->max_sess
= astat
->max_cfg_sess
= adapter
->sessionsLen
;
699 static UCHAR
nbDispatch(NetBIOSAdapter
*adapter
, PNCB ncb
)
703 TRACE(": adapter %p, ncb %p\n", adapter
, ncb
);
705 if (!adapter
) return NRC_BRIDGE
;
706 if (!ncb
) return NRC_INVADDRESS
;
708 cmd
= ncb
->ncb_command
& 0x7f;
710 ret
= nbReset(adapter
, ncb
);
713 ret
= NBCmdQueueAdd(adapter
->cmdQueue
, ncb
);
714 if (ret
== NRC_GOODRET
)
719 ret
= nbCall(adapter
, ncb
);
722 /* WinNT doesn't chain sends, it always sends immediately.
723 * Doubt there's any real significance to the NA variants.
729 ret
= nbSend(adapter
, ncb
);
733 ret
= nbRecv(adapter
, ncb
);
737 ret
= nbHangup(adapter
, ncb
);
741 ret
= nbAStat(adapter
, ncb
);
745 if (adapter
->transport
->findName
)
746 ret
= adapter
->transport
->findName(adapter
->impl
.data
,
753 FIXME("(%p): command code 0x%02x\n", ncb
, ncb
->ncb_command
);
756 NBCmdQueueComplete(adapter
->cmdQueue
, ncb
, ret
);
759 TRACE("returning 0x%02x\n", ret
);
763 static DWORD WINAPI
nbCmdThread(LPVOID lpVoid
)
770 NetBIOSAdapter
*adapter
= nbGetAdapter(ncb
->ncb_lana_num
);
773 ret
= nbDispatch(adapter
, ncb
);
776 ncb
->ncb_retcode
= ncb
->ncb_cmd_cplt
= ret
;
779 else if (ncb
->ncb_event
)
780 SetEvent(ncb
->ncb_event
);
785 UCHAR WINAPI
Netbios(PNCB ncb
)
789 TRACE("ncb = %p\n", ncb
);
791 if (!ncb
) return NRC_INVADDRESS
;
793 TRACE("ncb_command 0x%02x, ncb_lana_num %d, ncb_buffer %p, ncb_length %d\n",
794 ncb
->ncb_command
, ncb
->ncb_lana_num
, ncb
->ncb_buffer
, ncb
->ncb_length
);
795 cmd
= ncb
->ncb_command
& 0x7f;
798 ncb
->ncb_retcode
= ncb
->ncb_cmd_cplt
= ret
= nbEnum(ncb
);
799 else if (cmd
== NCBADDNAME
)
801 FIXME("NCBADDNAME: stub, returning success\n");
802 ncb
->ncb_retcode
= ncb
->ncb_cmd_cplt
= ret
= NRC_GOODRET
;
806 NetBIOSAdapter
*adapter
;
808 /* Apps not specifically written for WinNT won't do an NCBENUM first,
809 * so make sure the table has been enumerated at least once
811 if (!gNBTable
.enumerated
)
813 adapter
= nbGetAdapter(ncb
->ncb_lana_num
);
818 if (adapter
->shuttingDown
)
820 else if (adapter
->resetting
)
824 /* non-asynch commands first */
825 if (cmd
== NCBCANCEL
)
826 ncb
->ncb_retcode
= ncb
->ncb_cmd_cplt
= ret
=
827 nbCancel(adapter
, ncb
);
828 else if (cmd
== NCBSSTAT
)
829 ncb
->ncb_retcode
= ncb
->ncb_cmd_cplt
= ret
=
830 nbSStat(adapter
, ncb
);
833 if (ncb
->ncb_command
& ASYNCH
)
835 HANDLE thread
= CreateThread(NULL
, 0, nbCmdThread
, ncb
,
836 CREATE_SUSPENDED
, NULL
);
840 ncb
->ncb_retcode
= ncb
->ncb_cmd_cplt
= NRC_PENDING
;
842 ResetEvent(ncb
->ncb_event
);
843 ResumeThread(thread
);
848 ncb
->ncb_retcode
= ncb
->ncb_cmd_cplt
= ret
=
852 ncb
->ncb_retcode
= ncb
->ncb_cmd_cplt
= ret
=
853 nbDispatch(adapter
, ncb
);
858 TRACE("returning 0x%02x\n", ret
);