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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 reenabling
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
= (NetBIOSAdapter
*)HeapReAlloc(GetProcessHeap(),
88 HEAP_ZERO_MEMORY
, gNBTable
.table
,
89 newSize
* sizeof(NetBIOSAdapter
));
91 gNBTable
.table
= (NetBIOSAdapter
*)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
);
109 void NetBIOSShutdown(void)
113 EnterCriticalSection(&gNBTable
.cs
);
114 for (i
= 0; i
< gNBTable
.tableSize
; i
++)
116 if (gNBTable
.table
[i
].transport
&&
117 gNBTable
.table
[i
].transport
->cleanupAdapter
)
118 gNBTable
.table
[i
].transport
->cleanupAdapter(
119 gNBTable
.table
[i
].impl
.data
);
121 for (i
= 0; i
< gNumTransports
; i
++)
122 if (gTransports
[i
].transport
.cleanup
)
123 gTransports
[i
].transport
.cleanup();
124 LeaveCriticalSection(&gNBTable
.cs
);
125 DeleteCriticalSection(&gNBTable
.cs
);
126 HeapFree(GetProcessHeap(), 0, gNBTable
.table
);
129 BOOL
NetBIOSRegisterTransport(ULONG id
, NetBIOSTransport
*transport
)
133 TRACE(": transport 0x%08lx, p %p\n", id
, transport
);
136 else if (gNumTransports
>= sizeof(gTransports
) / sizeof(gTransports
[0]))
138 FIXME("You tried to add %d transports, but I only have space for %d\n",
139 gNumTransports
+ 1, sizeof(gTransports
) / sizeof(gTransports
[0]));
147 for (i
= 0; !ret
&& i
< gNumTransports
; i
++)
149 if (gTransports
[i
].id
== id
)
151 WARN("Replacing NetBIOS transport ID %ld\n", id
);
152 memcpy(&gTransports
[i
].transport
, transport
,
153 sizeof(NetBIOSTransport
));
159 gTransports
[gNumTransports
].id
= id
;
160 memcpy(&gTransports
[gNumTransports
].transport
, transport
,
161 sizeof(NetBIOSTransport
));
166 TRACE("returning %d\n", ret
);
170 /* In this, I acquire the table lock to make sure no one else is modifying it.
171 * This is _probably_ overkill since it should only be called during the
172 * context of a NetBIOSEnum call, but just to be safe..
174 BOOL
NetBIOSRegisterAdapter(ULONG transport
, DWORD ifIndex
, void *data
)
179 TRACE(": transport 0x%08lx, ifIndex 0x%08lx, data %p\n", transport
, ifIndex
,
181 for (i
= 0; i
< gNumTransports
&& gTransports
[i
].id
!= transport
; i
++)
183 if (gTransports
[i
].id
== transport
)
185 NetBIOSTransport
*transportPtr
= &gTransports
[i
].transport
;
187 TRACE(": found transport %p for id 0x%08lx\n", transportPtr
, transport
);
189 EnterCriticalSection(&gNBTable
.cs
);
191 for (i
= 0; i
< gNBTable
.tableSize
&&
192 gNBTable
.table
[i
].transport
!= 0; i
++)
194 if (i
== gNBTable
.tableSize
&& gNBTable
.tableSize
< MAX_LANA
+ 1)
198 if (gNBTable
.tableSize
< (MAX_LANA
+ 1) - ADAPTERS_INCR
)
199 newSize
= gNBTable
.tableSize
+ ADAPTERS_INCR
;
201 newSize
= MAX_LANA
+ 1;
202 nbResizeAdapterTable(newSize
);
204 if (i
< gNBTable
.tableSize
&& gNBTable
.table
[i
].transport
== 0)
206 TRACE(": registering as LANA %d\n", i
);
207 gNBTable
.table
[i
].transport_id
= transport
;
208 gNBTable
.table
[i
].transport
= transportPtr
;
209 gNBTable
.table
[i
].impl
.lana
= i
;
210 gNBTable
.table
[i
].impl
.ifIndex
= ifIndex
;
211 gNBTable
.table
[i
].impl
.data
= data
;
212 gNBTable
.table
[i
].cmdQueue
= NBCmdQueueCreate(GetProcessHeap());
213 InitializeCriticalSection(&gNBTable
.table
[i
].cs
);
214 gNBTable
.table
[i
].enabled
= TRUE
;
217 LeaveCriticalSection(&gNBTable
.cs
);
221 TRACE("returning %d\n", ret
);
225 /* In this, I acquire the table lock to make sure no one else is modifying it.
226 * This is _probably_ overkill since it should only be called during the
227 * context of a NetBIOSEnum call, but just to be safe..
229 void NetBIOSEnableAdapter(UCHAR lana
)
231 TRACE(": %d\n", lana
);
232 if (lana
< gNBTable
.tableSize
)
234 EnterCriticalSection(&gNBTable
.cs
);
235 if (gNBTable
.table
[lana
].transport
!= 0)
236 gNBTable
.table
[lana
].enabled
= TRUE
;
237 LeaveCriticalSection(&gNBTable
.cs
);
241 static void nbShutdownAdapter(NetBIOSAdapter
*adapter
)
245 adapter
->shuttingDown
= TRUE
;
246 NBCmdQueueCancelAll(adapter
->cmdQueue
);
247 if (adapter
->transport
->cleanupAdapter
)
248 adapter
->transport
->cleanupAdapter(adapter
->impl
.data
);
249 NBCmdQueueDestroy(adapter
->cmdQueue
);
250 DeleteCriticalSection(&adapter
->cs
);
251 memset(adapter
, 0, sizeof(NetBIOSAdapter
));
255 static void nbInternalEnum(void)
259 EnterCriticalSection(&gNBTable
.cs
);
260 TRACE("before mark\n");
262 for (i
= 0; i
< gNBTable
.tableSize
; i
++)
263 if (gNBTable
.table
[i
].enabled
&& gNBTable
.table
[i
].transport
!= 0)
264 gNBTable
.table
[i
].enabled
= FALSE
;
266 TRACE("marked, before store, %d transports\n", gNumTransports
);
267 /* store adapters: */
268 for (i
= 0; i
< gNumTransports
; i
++)
269 if (gTransports
[i
].transport
.enumerate
)
270 gTransports
[i
].transport
.enumerate();
272 TRACE("before sweep\n");
274 for (i
= 0; i
< gNBTable
.tableSize
; i
++)
275 if (!gNBTable
.table
[i
].enabled
&& gNBTable
.table
[i
].transport
!= 0)
276 nbShutdownAdapter(&gNBTable
.table
[i
]);
277 gNBTable
.enumerated
= TRUE
;
278 LeaveCriticalSection(&gNBTable
.cs
);
281 UCHAR
NetBIOSNumAdapters(void)
285 if (!gNBTable
.enumerated
)
287 for (i
= 0, ret
= 0; i
< gNBTable
.tableSize
; i
++)
288 if (gNBTable
.table
[i
].transport
!= 0)
293 void NetBIOSEnumAdapters(ULONG transport
, NetBIOSEnumAdaptersCallback cb
,
296 TRACE("transport 0x%08lx, callback %p, closure %p\n", transport
, cb
,
300 BOOL enumAll
= memcmp(&transport
, ALL_TRANSPORTS
, sizeof(ULONG
)) == 0;
301 UCHAR i
, numLANAs
= 0;
303 EnterCriticalSection(&gNBTable
.cs
);
304 if (!gNBTable
.enumerating
)
306 gNBTable
.enumerating
= TRUE
;
308 gNBTable
.enumerating
= FALSE
;
310 for (i
= 0; i
< gNBTable
.tableSize
; i
++)
311 if (enumAll
|| gNBTable
.table
[i
].transport_id
== transport
)
317 for (i
= 0; i
< gNBTable
.tableSize
; i
++)
318 if (gNBTable
.table
[i
].transport_id
!= 0 &&
319 (enumAll
|| gNBTable
.table
[i
].transport_id
== transport
))
320 cb(numLANAs
, lanaIndex
++, gNBTable
.table
[i
].transport_id
,
321 &gNBTable
.table
[i
].impl
, closure
);
323 LeaveCriticalSection(&gNBTable
.cs
);
327 static NetBIOSAdapter
*nbGetAdapter(UCHAR lana
)
329 NetBIOSAdapter
*ret
= NULL
;
331 TRACE(": lana %d, num allocated adapters %d\n", lana
, gNBTable
.tableSize
);
332 if (lana
< gNBTable
.tableSize
&& gNBTable
.table
[lana
].transport_id
!= 0
333 && gNBTable
.table
[lana
].transport
)
334 ret
= &gNBTable
.table
[lana
];
335 TRACE("returning %p\n", ret
);
339 static UCHAR
nbEnum(PNCB ncb
)
341 PLANA_ENUM lanas
= (PLANA_ENUM
)ncb
->ncb_buffer
;
344 TRACE(": ncb %p\n", ncb
);
348 else if (ncb
->ncb_length
< sizeof(LANA_ENUM
))
354 for (i
= 0; i
< gNBTable
.tableSize
; i
++)
355 if (gNBTable
.table
[i
].transport
)
362 TRACE("returning 0x%02x\n", ret
);
366 static UCHAR
nbInternalHangup(NetBIOSAdapter
*adapter
, NetBIOSSession
*session
);
368 static UCHAR
nbCancel(NetBIOSAdapter
*adapter
, PNCB ncb
)
372 TRACE(": adapter %p, ncb %p\n", adapter
, ncb
);
374 if (!adapter
) return NRC_BRIDGE
;
375 if (!ncb
) return NRC_INVADDRESS
;
377 switch (ncb
->ncb_command
& 0x7f)
388 /* NCBCALL, NCBCHAINSEND/NCBSEND, NCBHANGUP all close the associated
389 * session if cancelled */
397 if (ncb
->ncb_lsn
>= adapter
->sessionsLen
)
399 else if (!adapter
->sessions
[ncb
->ncb_lsn
].inUse
)
403 ret
= NBCmdQueueCancel(adapter
->cmdQueue
, ncb
);
404 if (ret
== NRC_CMDCAN
|| ret
== NRC_CANOCCR
)
405 nbInternalHangup(adapter
, &adapter
->sessions
[ncb
->ncb_lsn
]);
411 ret
= NBCmdQueueCancel(adapter
->cmdQueue
, ncb
);
413 TRACE("returning 0x%02x\n", ret
);
417 /* Resizes adapter to contain space for at least sessionsLen sessions.
418 * If allocating more space for sessions, sets the adapter's sessionsLen to
419 * sessionsLen. If the adapter's sessionsLen was already at least sessionsLen,
420 * does nothing. Does not modify existing sessions. Assumes the adapter is
422 * Returns NRC_GOODRET on success, and something else on failure.
424 static UCHAR
nbResizeAdapter(NetBIOSAdapter
*adapter
, UCHAR sessionsLen
)
426 UCHAR ret
= NRC_GOODRET
;
428 if (adapter
&& adapter
->sessionsLen
< sessionsLen
)
430 NetBIOSSession
*newSessions
;
432 if (adapter
->sessions
)
433 newSessions
= (NetBIOSSession
*)HeapReAlloc(GetProcessHeap(),
434 HEAP_ZERO_MEMORY
, adapter
->sessions
, sessionsLen
*
435 sizeof(NetBIOSSession
));
437 newSessions
= (NetBIOSSession
*)HeapAlloc(GetProcessHeap(),
438 HEAP_ZERO_MEMORY
, sessionsLen
* sizeof(NetBIOSSession
));
441 adapter
->sessions
= newSessions
;
442 adapter
->sessionsLen
= sessionsLen
;
445 ret
= NRC_OSRESNOTAV
;
450 static UCHAR
nbReset(NetBIOSAdapter
*adapter
, PNCB ncb
)
454 TRACE(": adapter %p, ncb %p\n", adapter
, ncb
);
456 if (!adapter
) return NRC_BRIDGE
;
457 if (!ncb
) return NRC_INVADDRESS
;
459 if (InterlockedIncrement(&adapter
->resetting
) == 1)
463 NBCmdQueueCancelAll(adapter
->cmdQueue
);
465 EnterCriticalSection(&adapter
->cs
);
466 for (i
= 0; i
< adapter
->sessionsLen
; i
++)
467 if (adapter
->sessions
[i
].inUse
)
468 nbInternalHangup(adapter
, &adapter
->sessions
[i
]);
470 resizeTo
= ncb
->ncb_callname
[0] == 0 ? DEFAULT_NUM_SESSIONS
:
471 ncb
->ncb_callname
[0];
472 else if (adapter
->sessionsLen
== 0)
473 resizeTo
= DEFAULT_NUM_SESSIONS
;
477 ret
= nbResizeAdapter(adapter
, resizeTo
);
480 LeaveCriticalSection(&adapter
->cs
);
484 InterlockedDecrement(&adapter
->resetting
);
485 TRACE("returning 0x%02x\n", ret
);
489 static UCHAR
nbSStat(NetBIOSAdapter
*adapter
, PNCB ncb
)
491 UCHAR ret
, i
, spaceFor
;
492 PSESSION_HEADER sstat
;
494 TRACE(": adapter %p, NCB %p\n", adapter
, ncb
);
496 if (!adapter
) return NRC_BADDR
;
497 if (adapter
->sessionsLen
== 0) return NRC_ENVNOTDEF
;
498 if (!ncb
) return NRC_INVADDRESS
;
499 if (!ncb
->ncb_buffer
) return NRC_BADDR
;
500 if (ncb
->ncb_length
< sizeof(SESSION_HEADER
)) return NRC_BUFLEN
;
502 sstat
= (PSESSION_HEADER
)ncb
->ncb_buffer
;
504 memset(sstat
, 0, sizeof(SESSION_HEADER
));
505 spaceFor
= (ncb
->ncb_length
- sizeof(SESSION_HEADER
)) /
506 sizeof(SESSION_BUFFER
);
507 EnterCriticalSection(&adapter
->cs
);
508 for (i
= 0; ret
== NRC_GOODRET
&& i
< adapter
->sessionsLen
; i
++)
510 if (adapter
->sessions
[i
].inUse
&& (ncb
->ncb_name
[0] == '*' ||
511 !memcmp(ncb
->ncb_name
, adapter
->sessions
[i
].local_name
, NCBNAMSZ
)))
513 if (sstat
->num_sess
< spaceFor
)
517 buf
= (PSESSION_BUFFER
)((PUCHAR
)sstat
+ sizeof(SESSION_HEADER
)
518 + sstat
->num_sess
* sizeof(SESSION_BUFFER
));
520 buf
->state
= adapter
->sessions
[i
].state
;
521 memcpy(buf
->local_name
, adapter
->sessions
[i
].local_name
,
523 memcpy(buf
->remote_name
, adapter
->sessions
[i
].remote_name
,
525 buf
->rcvs_outstanding
= buf
->sends_outstanding
= 0;
532 LeaveCriticalSection(&adapter
->cs
);
534 TRACE("returning 0x%02x\n", ret
);
538 static UCHAR
nbCall(NetBIOSAdapter
*adapter
, PNCB ncb
)
542 TRACE(": adapter %p, NCB %p\n", adapter
, ncb
);
544 if (!adapter
) return NRC_BRIDGE
;
545 if (adapter
->sessionsLen
== 0) return NRC_ENVNOTDEF
;
546 if (!adapter
->transport
->call
) return NRC_ILLCMD
;
547 if (!ncb
) return NRC_INVADDRESS
;
549 EnterCriticalSection(&adapter
->cs
);
550 for (i
= 0; i
< adapter
->sessionsLen
&& adapter
->sessions
[i
].inUse
; i
++)
552 if (i
< adapter
->sessionsLen
)
554 adapter
->sessions
[i
].inUse
= TRUE
;
555 adapter
->sessions
[i
].state
= CALL_PENDING
;
556 memcpy(adapter
->sessions
[i
].local_name
, ncb
->ncb_name
, NCBNAMSZ
);
557 memcpy(adapter
->sessions
[i
].remote_name
, ncb
->ncb_callname
, NCBNAMSZ
);
562 LeaveCriticalSection(&adapter
->cs
);
564 if (ret
== NRC_GOODRET
)
566 ret
= adapter
->transport
->call(adapter
->impl
.data
, ncb
,
567 &adapter
->sessions
[i
].data
);
568 if (ret
== NRC_GOODRET
)
571 adapter
->sessions
[i
].state
= SESSION_ESTABLISHED
;
575 adapter
->sessions
[i
].inUse
= FALSE
;
576 adapter
->sessions
[i
].state
= 0;
579 TRACE("returning 0x%02x\n", ret
);
583 static UCHAR
nbSend(NetBIOSAdapter
*adapter
, PNCB ncb
)
586 NetBIOSSession
*session
;
588 if (!adapter
) return NRC_BRIDGE
;
589 if (!adapter
->transport
->send
) return NRC_ILLCMD
;
590 if (!ncb
) return NRC_INVADDRESS
;
591 if (ncb
->ncb_lsn
>= adapter
->sessionsLen
) return NRC_SNUMOUT
;
592 if (!adapter
->sessions
[ncb
->ncb_lsn
].inUse
) return NRC_SNUMOUT
;
593 if (!ncb
->ncb_buffer
) return NRC_BADDR
;
595 session
= &adapter
->sessions
[ncb
->ncb_lsn
];
596 if (session
->state
!= SESSION_ESTABLISHED
)
599 ret
= adapter
->transport
->send(adapter
->impl
.data
, session
->data
, ncb
);
603 static UCHAR
nbRecv(NetBIOSAdapter
*adapter
, PNCB ncb
)
606 NetBIOSSession
*session
;
608 if (!adapter
) return NRC_BRIDGE
;
609 if (!adapter
->transport
->recv
) return NRC_ILLCMD
;
610 if (!ncb
) return NRC_INVADDRESS
;
611 if (ncb
->ncb_lsn
>= adapter
->sessionsLen
) return NRC_SNUMOUT
;
612 if (!adapter
->sessions
[ncb
->ncb_lsn
].inUse
) return NRC_SNUMOUT
;
613 if (!ncb
->ncb_buffer
) return NRC_BADDR
;
615 session
= &adapter
->sessions
[ncb
->ncb_lsn
];
616 if (session
->state
!= SESSION_ESTABLISHED
)
619 ret
= adapter
->transport
->recv(adapter
->impl
.data
, session
->data
, ncb
);
623 static UCHAR
nbInternalHangup(NetBIOSAdapter
*adapter
, NetBIOSSession
*session
)
627 if (!adapter
) return NRC_BRIDGE
;
628 if (!session
) return NRC_SNUMOUT
;
630 if (adapter
->transport
->hangup
)
631 ret
= adapter
->transport
->hangup(adapter
->impl
.data
, session
->data
);
634 EnterCriticalSection(&adapter
->cs
);
635 memset(session
, 0, sizeof(NetBIOSSession
));
636 LeaveCriticalSection(&adapter
->cs
);
640 static UCHAR
nbHangup(NetBIOSAdapter
*adapter
, PNCB ncb
)
643 NetBIOSSession
*session
;
645 if (!adapter
) return NRC_BRIDGE
;
646 if (!ncb
) return NRC_INVADDRESS
;
647 if (ncb
->ncb_lsn
>= adapter
->sessionsLen
) return NRC_SNUMOUT
;
648 if (!adapter
->sessions
[ncb
->ncb_lsn
].inUse
) return NRC_SNUMOUT
;
650 session
= &adapter
->sessions
[ncb
->ncb_lsn
];
651 if (session
->state
!= SESSION_ESTABLISHED
)
655 session
->state
= HANGUP_PENDING
;
656 ret
= nbInternalHangup(adapter
, session
);
661 void NetBIOSHangupSession(PNCB ncb
)
663 NetBIOSAdapter
*adapter
;
667 adapter
= nbGetAdapter(ncb
->ncb_lana_num
);
670 if (ncb
->ncb_lsn
< adapter
->sessionsLen
&&
671 adapter
->sessions
[ncb
->ncb_lsn
].inUse
)
672 nbHangup(adapter
, ncb
);
676 static UCHAR
nbAStat(NetBIOSAdapter
*adapter
, PNCB ncb
)
680 if (!adapter
) return NRC_BRIDGE
;
681 if (!adapter
->transport
->astat
) return NRC_ILLCMD
;
682 if (!ncb
) return NRC_INVADDRESS
;
683 if (!ncb
->ncb_buffer
) return NRC_BADDR
;
684 if (ncb
->ncb_length
< sizeof(ADAPTER_STATUS
)) return NRC_BUFLEN
;
686 ret
= adapter
->transport
->astat(adapter
->impl
.data
, ncb
);
687 if (ncb
->ncb_callname
[0] == '*')
689 PADAPTER_STATUS astat
= (PADAPTER_STATUS
)ncb
->ncb_buffer
;
691 astat
->max_sess
= astat
->max_cfg_sess
= adapter
->sessionsLen
;
696 static UCHAR
nbDispatch(NetBIOSAdapter
*adapter
, PNCB ncb
)
700 TRACE(": adapter %p, ncb %p\n", adapter
, ncb
);
702 if (!adapter
) return NRC_BRIDGE
;
703 if (!ncb
) return NRC_INVADDRESS
;
705 cmd
= ncb
->ncb_command
& 0x7f;
707 ret
= nbReset(adapter
, ncb
);
710 ret
= NBCmdQueueAdd(adapter
->cmdQueue
, ncb
);
711 if (ret
== NRC_GOODRET
)
716 ret
= nbCall(adapter
, ncb
);
719 /* WinNT doesn't chain sends, it always sends immediately.
720 * Doubt there's any real significance to the NA variants.
726 ret
= nbSend(adapter
, ncb
);
730 ret
= nbRecv(adapter
, ncb
);
734 ret
= nbHangup(adapter
, ncb
);
738 ret
= nbAStat(adapter
, ncb
);
742 if (adapter
->transport
->findName
)
743 ret
= adapter
->transport
->findName(adapter
->impl
.data
,
750 FIXME("(%p): command code 0x%02x\n", ncb
, ncb
->ncb_command
);
753 NBCmdQueueComplete(adapter
->cmdQueue
, ncb
, ret
);
756 TRACE("returning 0x%02x\n", ret
);
760 static DWORD WINAPI
nbCmdThread(LPVOID lpVoid
)
762 PNCB ncb
= (PNCB
)lpVoid
;
767 NetBIOSAdapter
*adapter
= nbGetAdapter(ncb
->ncb_lana_num
);
770 ret
= nbDispatch(adapter
, ncb
);
773 ncb
->ncb_retcode
= ncb
->ncb_cmd_cplt
= ret
;
776 else if (ncb
->ncb_event
)
777 SetEvent(ncb
->ncb_event
);
782 UCHAR WINAPI
Netbios(PNCB ncb
)
786 TRACE("ncb = %p\n", ncb
);
788 if (!ncb
) return NRC_INVADDRESS
;
790 TRACE("ncb_command 0x%02x, ncb_lana_num %d, ncb_buffer %p, ncb_length %d\n",
791 ncb
->ncb_command
, ncb
->ncb_lana_num
, ncb
->ncb_buffer
, ncb
->ncb_length
);
792 cmd
= ncb
->ncb_command
& 0x7f;
795 ncb
->ncb_retcode
= ncb
->ncb_cmd_cplt
= ret
= nbEnum(ncb
);
798 NetBIOSAdapter
*adapter
= nbGetAdapter(ncb
->ncb_lana_num
);
804 if (adapter
->shuttingDown
)
806 else if (adapter
->resetting
)
810 /* non-asynch commands first */
811 if (cmd
== NCBCANCEL
)
812 ncb
->ncb_retcode
= ncb
->ncb_cmd_cplt
= ret
=
813 nbCancel(adapter
, ncb
);
814 else if (cmd
== NCBSSTAT
)
815 ncb
->ncb_retcode
= ncb
->ncb_cmd_cplt
= ret
=
816 nbSStat(adapter
, ncb
);
819 if (ncb
->ncb_command
& ASYNCH
)
821 HANDLE thread
= CreateThread(NULL
, 0, nbCmdThread
, ncb
,
822 CREATE_SUSPENDED
, NULL
);
826 ncb
->ncb_retcode
= ncb
->ncb_cmd_cplt
= NRC_PENDING
;
828 ResetEvent(ncb
->ncb_event
);
829 ResumeThread(thread
);
834 ncb
->ncb_retcode
= ncb
->ncb_cmd_cplt
= ret
=
838 ncb
->ncb_retcode
= ncb
->ncb_cmd_cplt
= ret
=
839 nbDispatch(adapter
, ncb
);
844 TRACE("returning 0x%02x\n", ret
);