Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygennetbios.c
Go to the documentation of this file.
00001 /* Copyright (c) 2003 Juan Lang 00002 * 00003 * This library is free software; you can redistribute it and/or 00004 * modify it under the terms of the GNU Lesser General Public 00005 * License as published by the Free Software Foundation; either 00006 * version 2.1 of the License, or (at your option) any later version. 00007 * 00008 * This library is distributed in the hope that it will be useful, 00009 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00011 * Lesser General Public License for more details. 00012 * 00013 * You should have received a copy of the GNU Lesser General Public 00014 * License along with this library; if not, write to the Free Software 00015 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00016 */ 00017 #include "config.h" 00018 #include "wine/debug.h" 00019 #include "nbcmdqueue.h" 00020 #include "netbios.h" 00021 00022 WINE_DEFAULT_DEBUG_CHANNEL(netbios); 00023 00024 /* This file provides a NetBIOS emulator that implements the NetBIOS interface, 00025 * including thread safety and asynchronous call support. The protocol 00026 * implementation is separate, with blocking (synchronous) functions. 00027 */ 00028 00029 #define ADAPTERS_INCR 8 00030 #define DEFAULT_NUM_SESSIONS 16 00031 00032 typedef struct _NetBIOSTransportTableEntry 00033 { 00034 ULONG id; 00035 NetBIOSTransport transport; 00036 } NetBIOSTransportTableEntry; 00037 00038 typedef struct _NetBIOSSession 00039 { 00040 BOOL inUse; 00041 UCHAR state; 00042 UCHAR local_name[NCBNAMSZ]; 00043 UCHAR remote_name[NCBNAMSZ]; 00044 void *data; 00045 } NetBIOSSession; 00046 00047 /* This struct needs a little explanation, unfortunately. enabled is only 00048 * used by nbInternalEnum (see). If transport_id is not 0 and transport 00049 * is not NULL, the adapter is considered valid. (transport is a pointer to 00050 * an entry in a NetBIOSTransportTableEntry.) data has data for the callers of 00051 * NetBIOSEnumAdapters to be able to see. The lana is repeated there, even 00052 * though I don't use it internally--it's for transports to use reenabling 00053 * adapters using NetBIOSEnableAdapter. 00054 */ 00055 typedef struct _NetBIOSAdapter 00056 { 00057 BOOL enabled; 00058 BOOL shuttingDown; 00059 LONG resetting; 00060 ULONG transport_id; 00061 NetBIOSTransport *transport; 00062 NetBIOSAdapterImpl impl; 00063 struct NBCmdQueue *cmdQueue; 00064 CRITICAL_SECTION cs; 00065 DWORD sessionsLen; 00066 NetBIOSSession *sessions; 00067 } NetBIOSAdapter; 00068 00069 typedef struct _NetBIOSAdapterTable { 00070 CRITICAL_SECTION cs; 00071 BOOL enumerated; 00072 BOOL enumerating; 00073 UCHAR tableSize; 00074 NetBIOSAdapter *table; 00075 } NetBIOSAdapterTable; 00076 00077 /* Just enough space for NBT right now */ 00078 static NetBIOSTransportTableEntry gTransports[1]; 00079 static UCHAR gNumTransports = 0; 00080 static NetBIOSAdapterTable gNBTable; 00081 00082 static UCHAR nbResizeAdapterTable(UCHAR newSize) 00083 { 00084 UCHAR ret; 00085 00086 if (gNBTable.table) 00087 gNBTable.table = HeapReAlloc(GetProcessHeap(), 00088 HEAP_ZERO_MEMORY, gNBTable.table, 00089 newSize * sizeof(NetBIOSAdapter)); 00090 else 00091 gNBTable.table = HeapAlloc(GetProcessHeap(), 00092 HEAP_ZERO_MEMORY, newSize * sizeof(NetBIOSAdapter)); 00093 if (gNBTable.table) 00094 { 00095 gNBTable.tableSize = newSize; 00096 ret = NRC_GOODRET; 00097 } 00098 else 00099 ret = NRC_OSRESNOTAV; 00100 return ret; 00101 } 00102 00103 void NetBIOSInit(void) 00104 { 00105 memset(&gNBTable, 0, sizeof(gNBTable)); 00106 InitializeCriticalSection(&gNBTable.cs); 00107 gNBTable.cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": NetBIOSAdapterTable.cs"); 00108 } 00109 00110 void NetBIOSShutdown(void) 00111 { 00112 UCHAR i; 00113 00114 EnterCriticalSection(&gNBTable.cs); 00115 for (i = 0; i < gNBTable.tableSize; i++) 00116 { 00117 if (gNBTable.table[i].transport && 00118 gNBTable.table[i].transport->cleanupAdapter) 00119 gNBTable.table[i].transport->cleanupAdapter( 00120 gNBTable.table[i].impl.data); 00121 } 00122 for (i = 0; i < gNumTransports; i++) 00123 if (gTransports[i].transport.cleanup) 00124 gTransports[i].transport.cleanup(); 00125 LeaveCriticalSection(&gNBTable.cs); 00126 gNBTable.cs.DebugInfo->Spare[0] = 0; 00127 DeleteCriticalSection(&gNBTable.cs); 00128 HeapFree(GetProcessHeap(), 0, gNBTable.table); 00129 } 00130 00131 BOOL NetBIOSRegisterTransport(ULONG id, NetBIOSTransport *transport) 00132 { 00133 BOOL ret; 00134 00135 TRACE(": transport 0x%08x, p %p\n", id, transport); 00136 if (!transport) 00137 ret = FALSE; 00138 else if (gNumTransports >= sizeof(gTransports) / sizeof(gTransports[0])) 00139 { 00140 FIXME("Too many transports %d\n", gNumTransports + 1); 00141 ret = FALSE; 00142 } 00143 else 00144 { 00145 UCHAR i; 00146 00147 ret = FALSE; 00148 for (i = 0; !ret && i < gNumTransports; i++) 00149 { 00150 if (gTransports[i].id == id) 00151 { 00152 WARN("Replacing NetBIOS transport ID %d\n", id); 00153 memcpy(&gTransports[i].transport, transport, 00154 sizeof(NetBIOSTransport)); 00155 ret = TRUE; 00156 } 00157 } 00158 if (!ret) 00159 { 00160 gTransports[gNumTransports].id = id; 00161 memcpy(&gTransports[gNumTransports].transport, transport, 00162 sizeof(NetBIOSTransport)); 00163 gNumTransports++; 00164 ret = TRUE; 00165 } 00166 } 00167 TRACE("returning %d\n", ret); 00168 return ret; 00169 } 00170 00171 /* In this, I acquire the table lock to make sure no one else is modifying it. 00172 * This is _probably_ overkill since it should only be called during the 00173 * context of a NetBIOSEnum call, but just to be safe.. 00174 */ 00175 BOOL NetBIOSRegisterAdapter(ULONG transport, DWORD ifIndex, void *data) 00176 { 00177 BOOL ret; 00178 UCHAR i; 00179 00180 TRACE(": transport 0x%08x, ifIndex 0x%08x, data %p\n", transport, ifIndex, 00181 data); 00182 for (i = 0; i < gNumTransports && gTransports[i].id != transport; i++) 00183 ; 00184 if ((i < gNumTransports) && gTransports[i].id == transport) 00185 { 00186 NetBIOSTransport *transportPtr = &gTransports[i].transport; 00187 00188 TRACE(": found transport %p for id 0x%08x\n", transportPtr, transport); 00189 00190 EnterCriticalSection(&gNBTable.cs); 00191 ret = FALSE; 00192 for (i = 0; i < gNBTable.tableSize && 00193 gNBTable.table[i].transport != 0; i++) 00194 ; 00195 if (i == gNBTable.tableSize && gNBTable.tableSize < MAX_LANA + 1) 00196 { 00197 UCHAR newSize; 00198 00199 if (gNBTable.tableSize < (MAX_LANA + 1) - ADAPTERS_INCR) 00200 newSize = gNBTable.tableSize + ADAPTERS_INCR; 00201 else 00202 newSize = MAX_LANA + 1; 00203 nbResizeAdapterTable(newSize); 00204 } 00205 if (i < gNBTable.tableSize && gNBTable.table[i].transport == 0) 00206 { 00207 TRACE(": registering as LANA %d\n", i); 00208 gNBTable.table[i].transport_id = transport; 00209 gNBTable.table[i].transport = transportPtr; 00210 gNBTable.table[i].impl.lana = i; 00211 gNBTable.table[i].impl.ifIndex = ifIndex; 00212 gNBTable.table[i].impl.data = data; 00213 gNBTable.table[i].cmdQueue = NBCmdQueueCreate(GetProcessHeap()); 00214 InitializeCriticalSection(&gNBTable.table[i].cs); 00215 gNBTable.table[i].cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": NetBIOSAdapterTable.NetBIOSAdapter.cs"); 00216 gNBTable.table[i].enabled = TRUE; 00217 ret = TRUE; 00218 } 00219 LeaveCriticalSection(&gNBTable.cs); 00220 } 00221 else 00222 ret = FALSE; 00223 TRACE("returning %d\n", ret); 00224 return ret; 00225 } 00226 00227 /* In this, I acquire the table lock to make sure no one else is modifying it. 00228 * This is _probably_ overkill since it should only be called during the 00229 * context of a NetBIOSEnum call, but just to be safe.. 00230 */ 00231 void NetBIOSEnableAdapter(UCHAR lana) 00232 { 00233 TRACE(": %d\n", lana); 00234 if (lana < gNBTable.tableSize) 00235 { 00236 EnterCriticalSection(&gNBTable.cs); 00237 if (gNBTable.table[lana].transport != 0) 00238 gNBTable.table[lana].enabled = TRUE; 00239 LeaveCriticalSection(&gNBTable.cs); 00240 } 00241 } 00242 00243 static void nbShutdownAdapter(NetBIOSAdapter *adapter) 00244 { 00245 if (adapter) 00246 { 00247 adapter->shuttingDown = TRUE; 00248 NBCmdQueueCancelAll(adapter->cmdQueue); 00249 if (adapter->transport->cleanupAdapter) 00250 adapter->transport->cleanupAdapter(adapter->impl.data); 00251 NBCmdQueueDestroy(adapter->cmdQueue); 00252 adapter->cs.DebugInfo->Spare[0] = 0; 00253 DeleteCriticalSection(&adapter->cs); 00254 memset(adapter, 0, sizeof(NetBIOSAdapter)); 00255 } 00256 } 00257 00258 static void nbInternalEnum(void) 00259 { 00260 UCHAR i; 00261 00262 EnterCriticalSection(&gNBTable.cs); 00263 TRACE("before mark\n"); 00264 /* mark: */ 00265 for (i = 0; i < gNBTable.tableSize; i++) 00266 if (gNBTable.table[i].enabled && gNBTable.table[i].transport != 0) 00267 gNBTable.table[i].enabled = FALSE; 00268 00269 TRACE("marked, before store, %d transports\n", gNumTransports); 00270 /* store adapters: */ 00271 for (i = 0; i < gNumTransports; i++) 00272 if (gTransports[i].transport.enumerate) 00273 gTransports[i].transport.enumerate(); 00274 00275 TRACE("before sweep\n"); 00276 /* sweep: */ 00277 for (i = 0; i < gNBTable.tableSize; i++) 00278 if (!gNBTable.table[i].enabled && gNBTable.table[i].transport != 0) 00279 nbShutdownAdapter(&gNBTable.table[i]); 00280 gNBTable.enumerated = TRUE; 00281 LeaveCriticalSection(&gNBTable.cs); 00282 } 00283 00284 UCHAR NetBIOSNumAdapters(void) 00285 { 00286 UCHAR ret, i; 00287 00288 if (!gNBTable.enumerated) 00289 nbInternalEnum(); 00290 for (i = 0, ret = 0; i < gNBTable.tableSize; i++) 00291 if (gNBTable.table[i].transport != 0) 00292 ret++; 00293 return ret; 00294 } 00295 00296 void NetBIOSEnumAdapters(ULONG transport, NetBIOSEnumAdaptersCallback cb, 00297 void *closure) 00298 { 00299 TRACE("transport 0x%08x, callback %p, closure %p\n", transport, cb, 00300 closure); 00301 if (cb) 00302 { 00303 BOOL enumAll = memcmp(&transport, ALL_TRANSPORTS, sizeof(ULONG)) == 0; 00304 UCHAR i, numLANAs = 0; 00305 00306 EnterCriticalSection(&gNBTable.cs); 00307 if (!gNBTable.enumerating) 00308 { 00309 gNBTable.enumerating = TRUE; 00310 nbInternalEnum(); 00311 gNBTable.enumerating = FALSE; 00312 } 00313 for (i = 0; i < gNBTable.tableSize; i++) 00314 if (enumAll || gNBTable.table[i].transport_id == transport) 00315 numLANAs++; 00316 if (numLANAs > 0) 00317 { 00318 UCHAR lanaIndex = 0; 00319 00320 for (i = 0; i < gNBTable.tableSize; i++) 00321 if (gNBTable.table[i].transport_id != 0 && 00322 (enumAll || gNBTable.table[i].transport_id == transport)) 00323 cb(numLANAs, lanaIndex++, gNBTable.table[i].transport_id, 00324 &gNBTable.table[i].impl, closure); 00325 } 00326 LeaveCriticalSection(&gNBTable.cs); 00327 } 00328 } 00329 00330 static NetBIOSAdapter *nbGetAdapter(UCHAR lana) 00331 { 00332 NetBIOSAdapter *ret = NULL; 00333 00334 TRACE(": lana %d, num allocated adapters %d\n", lana, gNBTable.tableSize); 00335 if (lana < gNBTable.tableSize && gNBTable.table[lana].transport_id != 0 00336 && gNBTable.table[lana].transport) 00337 ret = &gNBTable.table[lana]; 00338 TRACE("returning %p\n", ret); 00339 return ret; 00340 } 00341 00342 static UCHAR nbEnum(PNCB ncb) 00343 { 00344 PLANA_ENUM lanas = (PLANA_ENUM)ncb->ncb_buffer; 00345 UCHAR i, ret; 00346 00347 TRACE(": ncb %p\n", ncb); 00348 00349 if (!lanas) 00350 ret = NRC_BUFLEN; 00351 else if (ncb->ncb_length < sizeof(LANA_ENUM)) 00352 ret = NRC_BUFLEN; 00353 else 00354 { 00355 nbInternalEnum(); 00356 lanas->length = 0; 00357 for (i = 0; i < gNBTable.tableSize; i++) 00358 if (gNBTable.table[i].transport) 00359 { 00360 lanas->length++; 00361 lanas->lana[i] = i; 00362 } 00363 ret = NRC_GOODRET; 00364 } 00365 TRACE("returning 0x%02x\n", ret); 00366 return ret; 00367 } 00368 00369 static UCHAR nbInternalHangup(NetBIOSAdapter *adapter, NetBIOSSession *session); 00370 00371 static UCHAR nbCancel(NetBIOSAdapter *adapter, PNCB ncb) 00372 { 00373 UCHAR ret; 00374 00375 TRACE(": adapter %p, ncb %p\n", adapter, ncb); 00376 00377 if (!adapter) return NRC_BRIDGE; 00378 if (!ncb) return NRC_INVADDRESS; 00379 00380 switch (ncb->ncb_command & 0x7f) 00381 { 00382 case NCBCANCEL: 00383 case NCBADDNAME: 00384 case NCBADDGRNAME: 00385 case NCBDELNAME: 00386 case NCBRESET: 00387 case NCBSSTAT: 00388 ret = NRC_CANCEL; 00389 break; 00390 00391 /* NCBCALL, NCBCHAINSEND/NCBSEND, NCBHANGUP all close the associated 00392 * session if cancelled */ 00393 case NCBCALL: 00394 case NCBSEND: 00395 case NCBCHAINSEND: 00396 case NCBSENDNA: 00397 case NCBCHAINSENDNA: 00398 case NCBHANGUP: 00399 { 00400 if (ncb->ncb_lsn >= adapter->sessionsLen) 00401 ret = NRC_SNUMOUT; 00402 else if (!adapter->sessions[ncb->ncb_lsn].inUse) 00403 ret = NRC_SNUMOUT; 00404 else 00405 { 00406 ret = NBCmdQueueCancel(adapter->cmdQueue, ncb); 00407 if (ret == NRC_CMDCAN || ret == NRC_CANOCCR) 00408 nbInternalHangup(adapter, &adapter->sessions[ncb->ncb_lsn]); 00409 } 00410 break; 00411 } 00412 00413 default: 00414 ret = NBCmdQueueCancel(adapter->cmdQueue, ncb); 00415 } 00416 TRACE("returning 0x%02x\n", ret); 00417 return ret; 00418 } 00419 00420 /* Resizes adapter to contain space for at least sessionsLen sessions. 00421 * If allocating more space for sessions, sets the adapter's sessionsLen to 00422 * sessionsLen. If the adapter's sessionsLen was already at least sessionsLen, 00423 * does nothing. Does not modify existing sessions. Assumes the adapter is 00424 * locked. 00425 * Returns NRC_GOODRET on success, and something else on failure. 00426 */ 00427 static UCHAR nbResizeAdapter(NetBIOSAdapter *adapter, UCHAR sessionsLen) 00428 { 00429 UCHAR ret = NRC_GOODRET; 00430 00431 if (adapter && adapter->sessionsLen < sessionsLen) 00432 { 00433 NetBIOSSession *newSessions; 00434 00435 if (adapter->sessions) 00436 newSessions = HeapReAlloc(GetProcessHeap(), 00437 HEAP_ZERO_MEMORY, adapter->sessions, sessionsLen * 00438 sizeof(NetBIOSSession)); 00439 else 00440 newSessions = HeapAlloc(GetProcessHeap(), 00441 HEAP_ZERO_MEMORY, sessionsLen * sizeof(NetBIOSSession)); 00442 if (newSessions) 00443 { 00444 adapter->sessions = newSessions; 00445 adapter->sessionsLen = sessionsLen; 00446 } 00447 else 00448 ret = NRC_OSRESNOTAV; 00449 } 00450 return ret; 00451 } 00452 00453 static UCHAR nbReset(NetBIOSAdapter *adapter, PNCB ncb) 00454 { 00455 UCHAR ret; 00456 00457 TRACE(": adapter %p, ncb %p\n", adapter, ncb); 00458 00459 if (!adapter) return NRC_BRIDGE; 00460 if (!ncb) return NRC_INVADDRESS; 00461 00462 if (InterlockedIncrement(&adapter->resetting) == 1) 00463 { 00464 UCHAR i, resizeTo; 00465 00466 NBCmdQueueCancelAll(adapter->cmdQueue); 00467 00468 EnterCriticalSection(&adapter->cs); 00469 for (i = 0; i < adapter->sessionsLen; i++) 00470 if (adapter->sessions[i].inUse) 00471 nbInternalHangup(adapter, &adapter->sessions[i]); 00472 if (!ncb->ncb_lsn) 00473 resizeTo = ncb->ncb_callname[0] == 0 ? DEFAULT_NUM_SESSIONS : 00474 ncb->ncb_callname[0]; 00475 else if (adapter->sessionsLen == 0) 00476 resizeTo = DEFAULT_NUM_SESSIONS; 00477 else 00478 resizeTo = 0; 00479 if (resizeTo > 0) 00480 ret = nbResizeAdapter(adapter, resizeTo); 00481 else 00482 ret = NRC_GOODRET; 00483 LeaveCriticalSection(&adapter->cs); 00484 } 00485 else 00486 ret = NRC_TOOMANY; 00487 InterlockedDecrement(&adapter->resetting); 00488 TRACE("returning 0x%02x\n", ret); 00489 return ret; 00490 } 00491 00492 static UCHAR nbSStat(NetBIOSAdapter *adapter, PNCB ncb) 00493 { 00494 UCHAR ret, i, spaceFor; 00495 PSESSION_HEADER sstat; 00496 00497 TRACE(": adapter %p, NCB %p\n", adapter, ncb); 00498 00499 if (!adapter) return NRC_BADDR; 00500 if (adapter->sessionsLen == 0) return NRC_ENVNOTDEF; 00501 if (!ncb) return NRC_INVADDRESS; 00502 if (!ncb->ncb_buffer) return NRC_BADDR; 00503 if (ncb->ncb_length < sizeof(SESSION_HEADER)) return NRC_BUFLEN; 00504 00505 sstat = (PSESSION_HEADER)ncb->ncb_buffer; 00506 ret = NRC_GOODRET; 00507 memset(sstat, 0, sizeof(SESSION_HEADER)); 00508 spaceFor = (ncb->ncb_length - sizeof(SESSION_HEADER)) / 00509 sizeof(SESSION_BUFFER); 00510 EnterCriticalSection(&adapter->cs); 00511 for (i = 0; ret == NRC_GOODRET && i < adapter->sessionsLen; i++) 00512 { 00513 if (adapter->sessions[i].inUse && (ncb->ncb_name[0] == '*' || 00514 !memcmp(ncb->ncb_name, adapter->sessions[i].local_name, NCBNAMSZ))) 00515 { 00516 if (sstat->num_sess < spaceFor) 00517 { 00518 PSESSION_BUFFER buf; 00519 00520 buf = (PSESSION_BUFFER)((PUCHAR)sstat + sizeof(SESSION_HEADER) 00521 + sstat->num_sess * sizeof(SESSION_BUFFER)); 00522 buf->lsn = i; 00523 buf->state = adapter->sessions[i].state; 00524 memcpy(buf->local_name, adapter->sessions[i].local_name, 00525 NCBNAMSZ); 00526 memcpy(buf->remote_name, adapter->sessions[i].remote_name, 00527 NCBNAMSZ); 00528 buf->rcvs_outstanding = buf->sends_outstanding = 0; 00529 sstat->num_sess++; 00530 } 00531 else 00532 ret = NRC_BUFLEN; 00533 } 00534 } 00535 LeaveCriticalSection(&adapter->cs); 00536 00537 TRACE("returning 0x%02x\n", ret); 00538 return ret; 00539 } 00540 00541 static UCHAR nbCall(NetBIOSAdapter *adapter, PNCB ncb) 00542 { 00543 UCHAR ret, i; 00544 00545 TRACE(": adapter %p, NCB %p\n", adapter, ncb); 00546 00547 if (!adapter) return NRC_BRIDGE; 00548 if (adapter->sessionsLen == 0) return NRC_ENVNOTDEF; 00549 if (!adapter->transport->call) return NRC_ILLCMD; 00550 if (!ncb) return NRC_INVADDRESS; 00551 00552 EnterCriticalSection(&adapter->cs); 00553 for (i = 0; i < adapter->sessionsLen && adapter->sessions[i].inUse; i++) 00554 ; 00555 if (i < adapter->sessionsLen) 00556 { 00557 adapter->sessions[i].inUse = TRUE; 00558 adapter->sessions[i].state = CALL_PENDING; 00559 memcpy(adapter->sessions[i].local_name, ncb->ncb_name, NCBNAMSZ); 00560 memcpy(adapter->sessions[i].remote_name, ncb->ncb_callname, NCBNAMSZ); 00561 ret = NRC_GOODRET; 00562 } 00563 else 00564 ret = NRC_LOCTFUL; 00565 LeaveCriticalSection(&adapter->cs); 00566 00567 if (ret == NRC_GOODRET) 00568 { 00569 ret = adapter->transport->call(adapter->impl.data, ncb, 00570 &adapter->sessions[i].data); 00571 if (ret == NRC_GOODRET) 00572 { 00573 ncb->ncb_lsn = i; 00574 adapter->sessions[i].state = SESSION_ESTABLISHED; 00575 } 00576 else 00577 { 00578 adapter->sessions[i].inUse = FALSE; 00579 adapter->sessions[i].state = 0; 00580 } 00581 } 00582 TRACE("returning 0x%02x\n", ret); 00583 return ret; 00584 } 00585 00586 static UCHAR nbSend(NetBIOSAdapter *adapter, PNCB ncb) 00587 { 00588 UCHAR ret; 00589 NetBIOSSession *session; 00590 00591 if (!adapter) return NRC_BRIDGE; 00592 if (!adapter->transport->send) return NRC_ILLCMD; 00593 if (!ncb) return NRC_INVADDRESS; 00594 if (ncb->ncb_lsn >= adapter->sessionsLen) return NRC_SNUMOUT; 00595 if (!adapter->sessions[ncb->ncb_lsn].inUse) return NRC_SNUMOUT; 00596 if (!ncb->ncb_buffer) return NRC_BADDR; 00597 00598 session = &adapter->sessions[ncb->ncb_lsn]; 00599 if (session->state != SESSION_ESTABLISHED) 00600 ret = NRC_SNUMOUT; 00601 else 00602 ret = adapter->transport->send(adapter->impl.data, session->data, ncb); 00603 return ret; 00604 } 00605 00606 static UCHAR nbRecv(NetBIOSAdapter *adapter, PNCB ncb) 00607 { 00608 UCHAR ret; 00609 NetBIOSSession *session; 00610 00611 if (!adapter) return NRC_BRIDGE; 00612 if (!adapter->transport->recv) return NRC_ILLCMD; 00613 if (!ncb) return NRC_INVADDRESS; 00614 if (ncb->ncb_lsn >= adapter->sessionsLen) return NRC_SNUMOUT; 00615 if (!adapter->sessions[ncb->ncb_lsn].inUse) return NRC_SNUMOUT; 00616 if (!ncb->ncb_buffer) return NRC_BADDR; 00617 00618 session = &adapter->sessions[ncb->ncb_lsn]; 00619 if (session->state != SESSION_ESTABLISHED) 00620 ret = NRC_SNUMOUT; 00621 else 00622 ret = adapter->transport->recv(adapter->impl.data, session->data, ncb); 00623 return ret; 00624 } 00625 00626 static UCHAR nbInternalHangup(NetBIOSAdapter *adapter, NetBIOSSession *session) 00627 { 00628 UCHAR ret; 00629 00630 if (!adapter) return NRC_BRIDGE; 00631 if (!session) return NRC_SNUMOUT; 00632 00633 if (adapter->transport->hangup) 00634 ret = adapter->transport->hangup(adapter->impl.data, session->data); 00635 else 00636 ret = NRC_ILLCMD; 00637 EnterCriticalSection(&adapter->cs); 00638 memset(session, 0, sizeof(NetBIOSSession)); 00639 LeaveCriticalSection(&adapter->cs); 00640 return ret; 00641 } 00642 00643 static UCHAR nbHangup(NetBIOSAdapter *adapter, const NCB *ncb) 00644 { 00645 UCHAR ret; 00646 NetBIOSSession *session; 00647 00648 if (!adapter) return NRC_BRIDGE; 00649 if (!ncb) return NRC_INVADDRESS; 00650 if (ncb->ncb_lsn >= adapter->sessionsLen) return NRC_SNUMOUT; 00651 if (!adapter->sessions[ncb->ncb_lsn].inUse) return NRC_SNUMOUT; 00652 00653 session = &adapter->sessions[ncb->ncb_lsn]; 00654 if (session->state != SESSION_ESTABLISHED) 00655 ret = NRC_SNUMOUT; 00656 else 00657 { 00658 session->state = HANGUP_PENDING; 00659 ret = nbInternalHangup(adapter, session); 00660 } 00661 return ret; 00662 } 00663 00664 void NetBIOSHangupSession(const NCB *ncb) 00665 { 00666 NetBIOSAdapter *adapter; 00667 00668 if (!ncb) return; 00669 00670 adapter = nbGetAdapter(ncb->ncb_lana_num); 00671 if (adapter) 00672 { 00673 if (ncb->ncb_lsn < adapter->sessionsLen && 00674 adapter->sessions[ncb->ncb_lsn].inUse) 00675 nbHangup(adapter, ncb); 00676 } 00677 } 00678 00679 static UCHAR nbAStat(NetBIOSAdapter *adapter, PNCB ncb) 00680 { 00681 UCHAR ret; 00682 00683 if (!adapter) return NRC_BRIDGE; 00684 if (!adapter->transport->astat) return NRC_ILLCMD; 00685 if (!ncb) return NRC_INVADDRESS; 00686 if (!ncb->ncb_buffer) return NRC_BADDR; 00687 if (ncb->ncb_length < sizeof(ADAPTER_STATUS)) return NRC_BUFLEN; 00688 00689 ret = adapter->transport->astat(adapter->impl.data, ncb); 00690 if (ncb->ncb_callname[0] == '*') 00691 { 00692 PADAPTER_STATUS astat = (PADAPTER_STATUS)ncb->ncb_buffer; 00693 00694 astat->max_sess = astat->max_cfg_sess = adapter->sessionsLen; 00695 } 00696 return ret; 00697 } 00698 00699 static UCHAR nbDispatch(NetBIOSAdapter *adapter, PNCB ncb) 00700 { 00701 UCHAR ret, cmd; 00702 00703 TRACE(": adapter %p, ncb %p\n", adapter, ncb); 00704 00705 if (!adapter) return NRC_BRIDGE; 00706 if (!ncb) return NRC_INVADDRESS; 00707 00708 cmd = ncb->ncb_command & 0x7f; 00709 if (cmd == NCBRESET) 00710 ret = nbReset(adapter, ncb); 00711 else 00712 { 00713 ret = NBCmdQueueAdd(adapter->cmdQueue, ncb); 00714 if (ret == NRC_GOODRET) 00715 { 00716 switch (cmd) 00717 { 00718 case NCBCALL: 00719 ret = nbCall(adapter, ncb); 00720 break; 00721 00722 /* WinNT doesn't chain sends, it always sends immediately. 00723 * Doubt there's any real significance to the NA variants. 00724 */ 00725 case NCBSEND: 00726 case NCBSENDNA: 00727 case NCBCHAINSEND: 00728 case NCBCHAINSENDNA: 00729 ret = nbSend(adapter, ncb); 00730 break; 00731 00732 case NCBRECV: 00733 ret = nbRecv(adapter, ncb); 00734 break; 00735 00736 case NCBHANGUP: 00737 ret = nbHangup(adapter, ncb); 00738 break; 00739 00740 case NCBASTAT: 00741 ret = nbAStat(adapter, ncb); 00742 break; 00743 00744 case NCBFINDNAME: 00745 if (adapter->transport->findName) 00746 ret = adapter->transport->findName(adapter->impl.data, 00747 ncb); 00748 else 00749 ret = NRC_ILLCMD; 00750 break; 00751 00752 default: 00753 FIXME("(%p): command code 0x%02x\n", ncb, ncb->ncb_command); 00754 ret = NRC_ILLCMD; 00755 } 00756 NBCmdQueueComplete(adapter->cmdQueue, ncb, ret); 00757 } 00758 } 00759 TRACE("returning 0x%02x\n", ret); 00760 return ret; 00761 } 00762 00763 static DWORD WINAPI nbCmdThread(LPVOID lpVoid) 00764 { 00765 PNCB ncb = lpVoid; 00766 00767 if (ncb) 00768 { 00769 UCHAR ret; 00770 NetBIOSAdapter *adapter = nbGetAdapter(ncb->ncb_lana_num); 00771 00772 if (adapter) 00773 ret = nbDispatch(adapter, ncb); 00774 else 00775 ret = NRC_BRIDGE; 00776 ncb->ncb_retcode = ncb->ncb_cmd_cplt = ret; 00777 if (ncb->ncb_post) 00778 ncb->ncb_post(ncb); 00779 else if (ncb->ncb_event) 00780 SetEvent(ncb->ncb_event); 00781 } 00782 return 0; 00783 } 00784 00785 UCHAR WINAPI Netbios(PNCB ncb) 00786 { 00787 UCHAR ret, cmd; 00788 00789 TRACE("ncb = %p\n", ncb); 00790 00791 if (!ncb) return NRC_INVADDRESS; 00792 00793 TRACE("ncb_command 0x%02x, ncb_lana_num %d, ncb_buffer %p, ncb_length %d\n", 00794 ncb->ncb_command, ncb->ncb_lana_num, ncb->ncb_buffer, ncb->ncb_length); 00795 cmd = ncb->ncb_command & 0x7f; 00796 00797 if (cmd == NCBENUM) 00798 ncb->ncb_retcode = ncb->ncb_cmd_cplt = ret = nbEnum(ncb); 00799 else if (cmd == NCBADDNAME) 00800 { 00801 FIXME("NCBADDNAME: stub, returning success\n"); 00802 ncb->ncb_retcode = ncb->ncb_cmd_cplt = ret = NRC_GOODRET; 00803 } 00804 else 00805 { 00806 NetBIOSAdapter *adapter; 00807 00808 /* Apps not specifically written for WinNT won't do an NCBENUM first, 00809 * so make sure the table has been enumerated at least once 00810 */ 00811 if (!gNBTable.enumerated) 00812 nbInternalEnum(); 00813 adapter = nbGetAdapter(ncb->ncb_lana_num); 00814 if (!adapter) 00815 ret = NRC_BRIDGE; 00816 else 00817 { 00818 if (adapter->shuttingDown) 00819 ret = NRC_IFBUSY; 00820 else if (adapter->resetting) 00821 ret = NRC_TOOMANY; 00822 else 00823 { 00824 /* non-asynch commands first */ 00825 if (cmd == NCBCANCEL) 00826 ncb->ncb_retcode = ncb->ncb_cmd_cplt = ret = 00827 nbCancel(adapter, ncb); 00828 else if (cmd == NCBSSTAT) 00829 ncb->ncb_retcode = ncb->ncb_cmd_cplt = ret = 00830 nbSStat(adapter, ncb); 00831 else 00832 { 00833 if (ncb->ncb_command & ASYNCH) 00834 { 00835 HANDLE thread = CreateThread(NULL, 0, nbCmdThread, ncb, 00836 CREATE_SUSPENDED, NULL); 00837 00838 if (thread != NULL) 00839 { 00840 ncb->ncb_retcode = ncb->ncb_cmd_cplt = NRC_PENDING; 00841 if (ncb->ncb_event) 00842 ResetEvent(ncb->ncb_event); 00843 ResumeThread(thread); 00844 CloseHandle(thread); 00845 ret = NRC_GOODRET; 00846 } 00847 else 00848 ncb->ncb_retcode = ncb->ncb_cmd_cplt = ret = 00849 NRC_OSRESNOTAV; 00850 } 00851 else 00852 ncb->ncb_retcode = ncb->ncb_cmd_cplt = ret = 00853 nbDispatch(adapter, ncb); 00854 } 00855 } 00856 } 00857 } 00858 TRACE("returning 0x%02x\n", ret); 00859 return ret; 00860 } Generated on Sun May 27 2012 04:25:27 for ReactOS by
1.7.6.1
|