ReactOS  0.4.13-dev-66-gc714b7f
nbt.c
Go to the documentation of this file.
1 /* Copyright (c) 2003 Juan Lang
2  *
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.
7  *
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.
12  *
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
16  *
17  * I am heavily indebted to Chris Hertel's excellent Implementing CIFS,
18  * http://ubiqx.org/cifs/ , for whatever understanding I have of NBT.
19  * I also stole from Mike McCormack's smb.c and netapi32.c, although little of
20  * that code remains.
21  * Lack of understanding and bugs are my fault.
22  *
23  * FIXME:
24  * - Of the NetBIOS session functions, only client functions are supported, and
25  * it's likely they'll be the only functions supported. NBT requires session
26  * servers to listen on TCP/139. This requires root privilege, and Samba is
27  * likely to be listening here already. This further restricts NetBIOS
28  * applications, both explicit users and implicit ones: CreateNamedPipe
29  * won't actually create a listening pipe, for example, so applications can't
30  * act as RPC servers using a named pipe protocol binding, DCOM won't be able
31  * to support callbacks or servers over the named pipe protocol, etc.
32  *
33  * - Datagram support is omitted for the same reason. To send a NetBIOS
34  * datagram, you must include the NetBIOS name by which your application is
35  * known. This requires you to have registered the name previously, and be
36  * able to act as a NetBIOS datagram server (listening on UDP/138).
37  *
38  * - Name registration functions are omitted for the same reason--registering a
39  * name requires you to be able to defend it, and this means listening on
40  * UDP/137.
41  * Win98 requires you either use your computer's NetBIOS name (with the NULL
42  * suffix byte) as the calling name when creating a session, or to register
43  * a new name before creating one: it disallows '*' as the calling name.
44  * Win2K initially starts with an empty name table, and doesn't allow you to
45  * use the machine's NetBIOS name (with the NULL suffix byte) as the calling
46  * name. Although it allows sessions to be created with '*' as the calling
47  * name, doing so results in timeouts for all receives, because the
48  * application never gets them.
49  * So, a well-behaved NetBIOS application will typically want to register a
50  * name. I should probably support a do-nothing name list that allows
51  * NCBADDNAME to add to it, but doesn't actually register the name, or does
52  * attempt to register it without being able to defend it.
53  *
54  * - Name lookups may not behave quite as you'd expect/like if you have
55  * multiple LANAs. If a name is resolvable through DNS, or if you're using
56  * WINS, it'll resolve on _any_ LANA. So, a Call will succeed on any LANA as
57  * well.
58  * I'm not sure how Windows behaves in this case. I could try to force
59  * lookups to the correct adapter by using one of the GetPreferred*
60  * functions, but with the possibility of multiple adapters in the same
61  * same subnet, there's no guarantee that what IpHlpApi thinks is the
62  * preferred adapter will actually be a LANA. (It's highly probable because
63  * this is an unusual configuration, but not guaranteed.)
64  *
65  * See also other FIXMEs in the code.
66  */
67 
68 #include "netapi32.h"
69 
70 #include <winsock2.h>
71 #include <winreg.h>
72 
74 
75 #define PORT_NBNS 137
76 #define PORT_NBDG 138
77 #define PORT_NBSS 139
78 
79 #ifndef INADDR_NONE
80 #define INADDR_NONE ~0UL
81 #endif
82 
83 #define NBR_ADDWORD(p,word) (*(WORD *)(p)) = htons(word)
84 #define NBR_GETWORD(p) ntohs(*(WORD *)(p))
85 
86 #define MIN_QUERIES 1
87 #define MAX_QUERIES 0xffff
88 #define MIN_QUERY_TIMEOUT 100
89 #define MAX_QUERY_TIMEOUT 0xffffffff
90 #define BCAST_QUERIES 3
91 #define BCAST_QUERY_TIMEOUT 750
92 #define WINS_QUERIES 3
93 #define WINS_QUERY_TIMEOUT 750
94 #define MAX_WINS_SERVERS 2
95 #define MIN_CACHE_TIMEOUT 60000
96 #define CACHE_TIMEOUT 360000
97 
98 #define MAX_NBT_NAME_SZ 255
99 #define SIMPLE_NAME_QUERY_PKT_SIZE 16 + MAX_NBT_NAME_SZ
100 
101 #define NBNS_TYPE_NB 0x0020
102 #define NBNS_TYPE_NBSTAT 0x0021
103 #define NBNS_CLASS_INTERNET 0x00001
104 #define NBNS_HEADER_SIZE (sizeof(WORD) * 6)
105 #define NBNS_RESPONSE_AND_OPCODE 0xf800
106 #define NBNS_RESPONSE_AND_QUERY 0x8000
107 #define NBNS_REPLYCODE 0x0f
108 
109 #define NBSS_HDRSIZE 4
110 
111 #define NBSS_MSG 0x00
112 #define NBSS_REQ 0x81
113 #define NBSS_ACK 0x82
114 #define NBSS_NACK 0x83
115 #define NBSS_RETARGET 0x84
116 #define NBSS_KEEPALIVE 0x85
117 
118 #define NBSS_ERR_NOT_LISTENING_ON_NAME 0x80
119 #define NBSS_ERR_NOT_LISTENING_FOR_CALLER 0x81
120 #define NBSS_ERR_BAD_NAME 0x82
121 #define NBSS_ERR_INSUFFICIENT_RESOURCES 0x83
122 
123 #define NBSS_EXTENSION 0x01
124 
125 typedef struct _NetBTSession
126 {
130 } NetBTSession;
131 
132 typedef struct _NetBTAdapter
133 {
139 } NetBTAdapter;
140 
148 static int gNumWINSServers;
151 static struct NBNameCache *gNameCache;
152 
153 /* Converts from a NetBIOS name into a Second Level Encoding-formatted name.
154  * Assumes p is not NULL and is either NULL terminated or has at most NCBNAMSZ
155  * bytes, and buffer has at least MAX_NBT_NAME_SZ bytes. Pads with space bytes
156  * if p is NULL-terminated. Returns the number of bytes stored in buffer.
157  */
158 static int NetBTNameEncode(const UCHAR *p, UCHAR *buffer)
159 {
160  int i,len=0;
161 
162  if (!p) return 0;
163  if (!buffer) return 0;
164 
165  buffer[len++] = NCBNAMSZ * 2;
166  for (i = 0; i < NCBNAMSZ && p[i]; i++)
167  {
168  buffer[len++] = ((p[i] & 0xf0) >> 4) + 'A';
169  buffer[len++] = (p[i] & 0x0f) + 'A';
170  }
171  while (len < NCBNAMSZ * 2)
172  {
173  buffer[len++] = 'C';
174  buffer[len++] = 'A';
175  }
176  if (*gScopeID)
177  {
178  int scopeIDLen = strlen(gScopeID);
179 
180  memcpy(buffer + len, gScopeID, scopeIDLen);
181  len += scopeIDLen;
182  }
183  buffer[len++] = 0; /* add second terminator */
184  return len;
185 }
186 
187 /* Creates a NBT name request packet for name in buffer. If broadcast is true,
188  * creates a broadcast request, otherwise creates a unicast request.
189  * Returns the number of bytes stored in buffer.
190  */
192  BOOL broadcast, UCHAR *buffer, int len)
193 {
194  int i = 0;
195 
196  if (len < SIMPLE_NAME_QUERY_PKT_SIZE) return 0;
197 
198  NBR_ADDWORD(&buffer[i],xid); i+=2; /* transaction */
199  if (broadcast)
200  {
201  NBR_ADDWORD(&buffer[i],0x0110); /* flags: r=req,op=query,rd=1,b=1 */
202  i+=2;
203  }
204  else
205  {
206  NBR_ADDWORD(&buffer[i],0x0100); /* flags: r=req,op=query,rd=1,b=0 */
207  i+=2;
208  }
209  NBR_ADDWORD(&buffer[i],0x0001); i+=2; /* one name query */
210  NBR_ADDWORD(&buffer[i],0x0000); i+=2; /* zero answers */
211  NBR_ADDWORD(&buffer[i],0x0000); i+=2; /* zero authorities */
212  NBR_ADDWORD(&buffer[i],0x0000); i+=2; /* zero additional */
213 
214  i += NetBTNameEncode(name, &buffer[i]);
215 
216  NBR_ADDWORD(&buffer[i],qtype); i+=2;
218 
219  return i;
220 }
221 
222 /* Sends a name query request for name on fd to destAddr. Sets SO_BROADCAST on
223  * fd if broadcast is TRUE. Assumes fd is not INVALID_SOCKET, and name is not
224  * NULL.
225  * Returns 0 on success, -1 on failure.
226  */
228  WORD qtype, DWORD destAddr, BOOL broadcast)
229 {
230  int ret = 0, on = 1;
231  struct in_addr addr;
232 
233  addr.s_addr = destAddr;
234  TRACE("name %s, dest addr %s\n", name, inet_ntoa(addr));
235 
236  if (broadcast)
237  ret = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (const char*)&on, sizeof(on));
238  if(ret == 0)
239  {
240  WSABUF wsaBuf;
242  struct sockaddr_in sin;
243 
244  memset(&sin, 0, sizeof(sin));
245  sin.sin_addr.s_addr = destAddr;
246  sin.sin_family = AF_INET;
247  sin.sin_port = htons(PORT_NBNS);
248 
249  wsaBuf.buf = (CHAR*)buf;
250  wsaBuf.len = NetBTNameReq(name, xid, qtype, broadcast, buf,
251  sizeof(buf));
252  if (wsaBuf.len > 0)
253  {
254  DWORD bytesSent;
255 
256  ret = WSASendTo(fd, &wsaBuf, 1, &bytesSent, 0,
257  (struct sockaddr*)&sin, sizeof(sin), NULL, NULL);
258  if (ret < 0 || bytesSent < wsaBuf.len)
259  ret = -1;
260  else
261  ret = 0;
262  }
263  else
264  ret = -1;
265  }
266  return ret;
267 }
268 
269 typedef BOOL (*NetBTAnswerCallback)(void *data, WORD answerCount,
270  WORD answerIndex, PUCHAR rData, WORD rdLength);
271 
272 /* Waits on fd until GetTickCount() returns a value greater than or equal to
273  * waitUntil for a name service response. If a name response matching xid
274  * is received, calls answerCallback once for each answer resource record in
275  * the response. (The callback's answerCount will be the total number of
276  * answers to expect, and answerIndex will be the 0-based index that's being
277  * sent this time.) Quits parsing if answerCallback returns FALSE.
278  * Returns NRC_GOODRET on timeout or a valid response received, something else
279  * on error.
280  */
282  DWORD waitUntil, NetBTAnswerCallback answerCallback, void *data)
283 {
284  BOOL found = FALSE;
285  DWORD now;
287 
288  if (!adapter) return NRC_BADDR;
289  if (fd == INVALID_SOCKET) return NRC_BADDR;
290  if (!answerCallback) return NRC_BADDR;
291 
292  while (!found && ret == NRC_GOODRET && (int)((now = GetTickCount()) - waitUntil) < 0)
293  {
294  DWORD msToWait = waitUntil - now;
295  struct fd_set fds;
296  struct timeval timeout = { msToWait / 1000, msToWait % 1000 };
297  int r;
298 
299  FD_ZERO(&fds);
300  FD_SET(fd, &fds);
301  r = select(fd + 1, &fds, NULL, NULL, &timeout);
302  if (r < 0)
303  ret = NRC_SYSTEM;
304  else if (r == 1)
305  {
306  /* FIXME: magic #, is this always enough? */
307  UCHAR buffer[256];
308  int fromsize;
309  struct sockaddr_in fromaddr;
310  WORD respXID, flags, queryCount, answerCount;
311  WSABUF wsaBuf = { sizeof(buffer), (CHAR*)buffer };
312  DWORD bytesReceived, recvFlags = 0;
313 
314  fromsize = sizeof(fromaddr);
315  r = WSARecvFrom(fd, &wsaBuf, 1, &bytesReceived, &recvFlags,
316  (struct sockaddr*)&fromaddr, &fromsize, NULL, NULL);
317  if(r < 0)
318  {
319  ret = NRC_SYSTEM;
320  break;
321  }
322 
323  if (bytesReceived < NBNS_HEADER_SIZE)
324  continue;
325 
326  respXID = NBR_GETWORD(buffer);
327  if (adapter->nameQueryXID != respXID)
328  continue;
329 
330  flags = NBR_GETWORD(buffer + 2);
331  queryCount = NBR_GETWORD(buffer + 4);
332  answerCount = NBR_GETWORD(buffer + 6);
333 
334  /* a reply shouldn't contain a query, ignore bad packet */
335  if (queryCount > 0)
336  continue;
337 
339  {
340  if ((flags & NBNS_REPLYCODE) != 0)
341  ret = NRC_NAMERR;
342  else if ((flags & NBNS_REPLYCODE) == 0 && answerCount > 0)
343  {
345  BOOL shouldContinue = TRUE;
346  WORD answerIndex = 0;
347 
348  found = TRUE;
349  /* decode one answer at a time */
350  while (ret == NRC_GOODRET && answerIndex < answerCount &&
351  ptr - buffer < bytesReceived && shouldContinue)
352  {
353  WORD rLen;
354 
355  /* scan past name */
356  for (; ptr[0] && ptr - buffer < bytesReceived; )
357  ptr += ptr[0] + 1;
358  ptr++;
359  ptr += 2; /* scan past type */
360  if (ptr - buffer < bytesReceived && ret == NRC_GOODRET
362  ptr += sizeof(WORD);
363  else
364  ret = NRC_SYSTEM; /* parse error */
365  ptr += sizeof(DWORD); /* TTL */
366  rLen = NBR_GETWORD(ptr);
367  rLen = min(rLen, bytesReceived - (ptr - buffer));
368  ptr += sizeof(WORD);
369  shouldContinue = answerCallback(data, answerCount,
370  answerIndex, ptr, rLen);
371  ptr += rLen;
372  answerIndex++;
373  }
374  }
375  }
376  }
377  }
378  TRACE("returning 0x%02x\n", ret);
379  return ret;
380 }
381 
382 typedef struct _NetBTNameQueryData {
386 
387 /* Name query callback function for NetBTWaitForNameResponse, creates a cache
388  * entry on the first answer, adds each address as it's called again (as long
389  * as there's space). If there's an error that should be propagated as the
390  * NetBIOS error, modifies queryData's ret member to the proper return code.
391  */
392 static BOOL NetBTFindNameAnswerCallback(void *pVoid, WORD answerCount,
393  WORD answerIndex, PUCHAR rData, WORD rLen)
394 {
395  NetBTNameQueryData *queryData = pVoid;
396  BOOL ret;
397 
398  if (queryData)
399  {
400  if (queryData->cacheEntry == NULL)
401  {
402  queryData->cacheEntry = HeapAlloc(GetProcessHeap(), 0,
403  FIELD_OFFSET(NBNameCacheEntry, addresses[answerCount]));
404  if (queryData->cacheEntry)
405  queryData->cacheEntry->numAddresses = 0;
406  else
407  queryData->ret = NRC_OSRESNOTAV;
408  }
409  if (rLen == 6 && queryData->cacheEntry &&
410  queryData->cacheEntry->numAddresses < answerCount)
411  {
412  queryData->cacheEntry->addresses[queryData->cacheEntry->
413  numAddresses++] = *(const DWORD *)(rData + 2);
414  ret = queryData->cacheEntry->numAddresses < answerCount;
415  }
416  else
417  ret = FALSE;
418  }
419  else
420  ret = FALSE;
421  return ret;
422 }
423 
424 /* Workhorse NetBT name lookup function. Sends a name lookup query for
425  * ncb->ncb_callname to sendTo, as a broadcast if broadcast is TRUE, using
426  * adapter->nameQueryXID as the transaction ID. Waits up to timeout
427  * milliseconds, and retries up to maxQueries times, waiting for a reply.
428  * If a valid response is received, stores the looked up addresses as a
429  * NBNameCacheEntry in *cacheEntry.
430  * Returns NRC_GOODRET on success, though this may not mean the name was
431  * resolved--check whether *cacheEntry is NULL.
432  */
433 static UCHAR NetBTNameWaitLoop(const NetBTAdapter *adapter, SOCKET fd, const NCB *ncb,
434  DWORD sendTo, BOOL broadcast, DWORD timeout, DWORD maxQueries,
435  NBNameCacheEntry **cacheEntry)
436 {
437  unsigned int queries;
438  NetBTNameQueryData queryData;
439 
440  if (!adapter) return NRC_BADDR;
441  if (fd == INVALID_SOCKET) return NRC_BADDR;
442  if (!ncb) return NRC_BADDR;
443  if (!cacheEntry) return NRC_BADDR;
444 
445  queryData.cacheEntry = NULL;
446  queryData.ret = NRC_GOODRET;
447  for (queries = 0; queryData.cacheEntry == NULL && queries < maxQueries;
448  queries++)
449  {
450  if (!NCB_CANCELLED(ncb))
451  {
452  int r = NetBTSendNameQuery(fd, ncb->ncb_callname,
453  adapter->nameQueryXID, NBNS_TYPE_NB, sendTo, broadcast);
454 
455  if (r == 0)
456  queryData.ret = NetBTWaitForNameResponse(adapter, fd,
458  &queryData);
459  else
460  queryData.ret = NRC_SYSTEM;
461  }
462  else
463  queryData.ret = NRC_CMDCAN;
464  }
465  if (queryData.cacheEntry)
466  {
467  memcpy(queryData.cacheEntry->name, ncb->ncb_callname, NCBNAMSZ);
468  memcpy(queryData.cacheEntry->nbname, ncb->ncb_callname, NCBNAMSZ);
469  }
470  *cacheEntry = queryData.cacheEntry;
471  return queryData.ret;
472 }
473 
474 /* Attempts to add cacheEntry to the name cache in *nameCache; if *nameCache
475  * has not yet been created, creates it, using gCacheTimeout as the cache
476  * entry timeout. If memory allocation fails, or if NBNameCacheAddEntry fails,
477  * frees cacheEntry.
478  * Returns NRC_GOODRET on success, and something else on failure.
479  */
480 static UCHAR NetBTStoreCacheEntry(struct NBNameCache **nameCache,
481  NBNameCacheEntry *cacheEntry)
482 {
483  UCHAR ret;
484 
485  if (!nameCache) return NRC_BADDR;
486  if (!cacheEntry) return NRC_BADDR;
487 
488  if (!*nameCache)
490  if (*nameCache)
491  ret = NBNameCacheAddEntry(*nameCache, cacheEntry)
493  else
494  {
495  HeapFree(GetProcessHeap(), 0, cacheEntry);
497  }
498  return ret;
499 }
500 
501 /* Attempts to resolve name using inet_addr(), then gethostbyname() if
502  * gEnableDNS is TRUE, if the suffix byte is either <00> or <20>. If the name
503  * can be looked up, returns 0 and stores the looked up addresses as a
504  * NBNameCacheEntry in *cacheEntry.
505  * Returns NRC_GOODRET on success, though this may not mean the name was
506  * resolved--check whether *cacheEntry is NULL. Returns something else on
507  * error.
508  */
510  NBNameCacheEntry **cacheEntry)
511 {
513 
514  TRACE("name %s, cacheEntry %p\n", name, cacheEntry);
515 
516  if (!name) return NRC_BADDR;
517  if (!cacheEntry) return NRC_BADDR;
518 
519  if (isalnum(name[0]) && (name[NCBNAMSZ - 1] == 0 ||
520  name[NCBNAMSZ - 1] == 0x20))
521  {
522  CHAR toLookup[NCBNAMSZ];
523  unsigned int i;
524 
525  for (i = 0; i < NCBNAMSZ - 1 && name[i] && name[i] != ' '; i++)
526  toLookup[i] = name[i];
527  toLookup[i] = '\0';
528 
529  if (isdigit(toLookup[0]))
530  {
531  unsigned long addr = inet_addr(toLookup);
532 
533  if (addr != INADDR_NONE)
534  {
535  *cacheEntry = HeapAlloc(GetProcessHeap(), 0,
536  FIELD_OFFSET(NBNameCacheEntry, addresses[1]));
537  if (*cacheEntry)
538  {
539  memcpy((*cacheEntry)->name, name, NCBNAMSZ);
540  memset((*cacheEntry)->nbname, 0, NCBNAMSZ);
541  (*cacheEntry)->nbname[0] = '*';
542  (*cacheEntry)->numAddresses = 1;
543  (*cacheEntry)->addresses[0] = addr;
544  }
545  else
547  }
548  }
549  if (gEnableDNS && ret == NRC_GOODRET && !*cacheEntry)
550  {
551  struct hostent *host;
552 
553  if ((host = gethostbyname(toLookup)) != NULL)
554  {
555  for (i = 0; ret == NRC_GOODRET && host->h_addr_list &&
556  host->h_addr_list[i]; i++)
557  ;
558  if (host->h_addr_list && host->h_addr_list[0])
559  {
560  *cacheEntry = HeapAlloc(GetProcessHeap(), 0,
561  FIELD_OFFSET(NBNameCacheEntry, addresses[i]));
562  if (*cacheEntry)
563  {
564  memcpy((*cacheEntry)->name, name, NCBNAMSZ);
565  memset((*cacheEntry)->nbname, 0, NCBNAMSZ);
566  (*cacheEntry)->nbname[0] = '*';
567  (*cacheEntry)->numAddresses = i;
568  for (i = 0; i < (*cacheEntry)->numAddresses; i++)
569  (*cacheEntry)->addresses[i] =
570  *(DWORD*)host->h_addr_list[i];
571  }
572  else
574  }
575  }
576  }
577  }
578 
579  TRACE("returning 0x%02x\n", ret);
580  return ret;
581 }
582 
583 /* Looks up the name in ncb->ncb_callname, first in the name caches (global
584  * and this adapter's), then using gethostbyname(), next by WINS if configured,
585  * and finally using broadcast NetBT name resolution. In NBT parlance, this
586  * makes this an "H-node". Stores an entry in the appropriate name cache for a
587  * found node, and returns it as *cacheEntry.
588  * Assumes data, ncb, and cacheEntry are not NULL.
589  * Returns NRC_GOODRET on success--which doesn't mean the name was resolved,
590  * just that all name lookup operations completed successfully--and something
591  * else on failure. *cacheEntry will be NULL if the name was not found.
592  */
594  const NBNameCacheEntry **cacheEntry)
595 {
597 
598  TRACE("adapter %p, ncb %p, cacheEntry %p\n", adapter, ncb, cacheEntry);
599 
600  if (!cacheEntry) return NRC_BADDR;
601  *cacheEntry = NULL;
602 
603  if (!adapter) return NRC_BADDR;
604  if (!ncb) return NRC_BADDR;
605 
606  if (ncb->ncb_callname[0] == '*')
607  ret = NRC_NOWILD;
608  else
609  {
610  *cacheEntry = NBNameCacheFindEntry(gNameCache, ncb->ncb_callname);
611  if (!*cacheEntry)
612  *cacheEntry = NBNameCacheFindEntry(adapter->nameCache,
613  ncb->ncb_callname);
614  if (!*cacheEntry)
615  {
616  NBNameCacheEntry *newEntry = NULL;
617 
618  ret = NetBTinetResolve(ncb->ncb_callname, &newEntry);
619  if (ret == NRC_GOODRET && newEntry)
620  {
621  ret = NetBTStoreCacheEntry(&gNameCache, newEntry);
622  if (ret != NRC_GOODRET)
623  newEntry = NULL;
624  }
625  else
626  {
629 
630  if(fd == INVALID_SOCKET)
632  else
633  {
634  int winsNdx;
635 
636  adapter->nameQueryXID++;
637  for (winsNdx = 0; ret == NRC_GOODRET && *cacheEntry == NULL
638  && winsNdx < gNumWINSServers; winsNdx++)
639  ret = NetBTNameWaitLoop(adapter, fd, ncb,
641  gWINSQueries, &newEntry);
642  if (ret == NRC_GOODRET && newEntry)
643  {
644  ret = NetBTStoreCacheEntry(&gNameCache, newEntry);
645  if (ret != NRC_GOODRET)
646  newEntry = NULL;
647  }
648  if (ret == NRC_GOODRET && *cacheEntry == NULL)
649  {
650  DWORD bcastAddr =
651  adapter->ipr.dwAddr & adapter->ipr.dwMask;
652 
653  if (adapter->ipr.dwBCastAddr)
654  bcastAddr |= ~adapter->ipr.dwMask;
655  ret = NetBTNameWaitLoop(adapter, fd, ncb, bcastAddr,
656  TRUE, gBCastQueryTimeout, gBCastQueries, &newEntry);
657  if (ret == NRC_GOODRET && newEntry)
658  {
659  ret = NetBTStoreCacheEntry(&adapter->nameCache,
660  newEntry);
661  if (ret != NRC_GOODRET)
662  newEntry = NULL;
663  }
664  }
665  closesocket(fd);
666  }
667  }
668  *cacheEntry = newEntry;
669  }
670  }
671  TRACE("returning 0x%02x\n", ret);
672  return ret;
673 }
674 
675 typedef struct _NetBTNodeQueryData
676 {
681 
682 /* Callback function for NetBTAstatRemote, parses the rData for the node
683  * status and name list of the remote node. Always returns FALSE, since
684  * there's never more than one answer we care about in a node status response.
685  */
686 static BOOL NetBTNodeStatusAnswerCallback(void *pVoid, WORD answerCount,
687  WORD answerIndex, PUCHAR rData, WORD rLen)
688 {
689  NetBTNodeQueryData *data = pVoid;
690 
691  if (data && !data->gotResponse && rData && rLen >= 1)
692  {
693  /* num names is first byte; each name is NCBNAMSZ + 2 bytes */
694  if (rLen >= rData[0] * (NCBNAMSZ + 2))
695  {
696  WORD i;
697  PUCHAR src;
699 
700  data->gotResponse = TRUE;
701  data->astat->name_count = rData[0];
702  for (i = 0, src = rData + 1,
703  dst = (PNAME_BUFFER)((PUCHAR)data->astat +
704  sizeof(ADAPTER_STATUS));
705  i < data->astat->name_count && src - rData < rLen &&
706  (PUCHAR)dst - (PUCHAR)data->astat < data->astatLen;
707  i++, dst++, src += NCBNAMSZ + 2)
708  {
709  UCHAR flags = *(src + NCBNAMSZ);
710 
711  memcpy(dst->name, src, NCBNAMSZ);
712  /* we won't actually see a registering name in the returned
713  * response. It's useful to see if no other flags are set; if
714  * none are, then the name is registered. */
715  dst->name_flags = REGISTERING;
716  if (flags & 0x80)
717  dst->name_flags |= GROUP_NAME;
718  if (flags & 0x10)
719  dst->name_flags |= DEREGISTERED;
720  if (flags & 0x08)
721  dst->name_flags |= DUPLICATE;
722  if (dst->name_flags == REGISTERING)
723  dst->name_flags = REGISTERED;
724  }
725  /* arbitrarily set HW type to Ethernet */
726  data->astat->adapter_type = 0xfe;
727  if (src - rData < rLen)
728  memcpy(data->astat->adapter_address, src,
729  min(rLen - (src - rData), 6));
730  }
731  }
732  return FALSE;
733 }
734 
735 /* This uses the WINS timeout and query values, as they're the
736  * UCAST_REQ_RETRY_TIMEOUT and UCAST_REQ_RETRY_COUNT according to the RFCs.
737  */
739 {
741  const NBNameCacheEntry *cacheEntry = NULL;
742 
743  TRACE("adapter %p, NCB %p\n", adapter, ncb);
744 
745  if (!adapter) return NRC_BADDR;
746  if (!ncb) return NRC_INVADDRESS;
747 
748  ret = NetBTInternalFindName(adapter, ncb, &cacheEntry);
749  if (ret == NRC_GOODRET && cacheEntry)
750  {
751  if (cacheEntry->numAddresses > 0)
752  {
755 
756  if(fd == INVALID_SOCKET)
758  else
759  {
760  NetBTNodeQueryData queryData;
761  DWORD queries;
763 
764  adapter->nameQueryXID++;
765  astat->name_count = 0;
766  queryData.gotResponse = FALSE;
767  queryData.astat = astat;
768  queryData.astatLen = ncb->ncb_length;
769  for (queries = 0; !queryData.gotResponse &&
770  queries < gWINSQueries; queries++)
771  {
772  if (!NCB_CANCELLED(ncb))
773  {
774  int r = NetBTSendNameQuery(fd, ncb->ncb_callname,
775  adapter->nameQueryXID, NBNS_TYPE_NBSTAT,
776  cacheEntry->addresses[0], FALSE);
777 
778  if (r == 0)
779  ret = NetBTWaitForNameResponse(adapter, fd,
781  NetBTNodeStatusAnswerCallback, &queryData);
782  else
783  ret = NRC_SYSTEM;
784  }
785  else
786  ret = NRC_CMDCAN;
787  }
788  closesocket(fd);
789  }
790  }
791  else
792  ret = NRC_CMDTMO;
793  }
794  else if (ret == NRC_CMDCAN)
795  ; /* do nothing, we were cancelled */
796  else
797  ret = NRC_CMDTMO;
798  TRACE("returning 0x%02x\n", ret);
799  return ret;
800 }
801 
802 static UCHAR NetBTAstat(void *adapt, PNCB ncb)
803 {
804  NetBTAdapter *adapter = adapt;
805  UCHAR ret;
806 
807  TRACE("adapt %p, NCB %p\n", adapt, ncb);
808 
809  if (!adapter) return NRC_ENVNOTDEF;
810  if (!ncb) return NRC_INVADDRESS;
811  if (!ncb->ncb_buffer) return NRC_BADDR;
812  if (ncb->ncb_length < sizeof(ADAPTER_STATUS)) return NRC_BUFLEN;
813 
814  if (ncb->ncb_callname[0] == '*')
815  {
816  DWORD physAddrLen;
817  MIB_IFROW ifRow;
819 
820  memset(astat, 0, sizeof(ADAPTER_STATUS));
821  astat->rev_major = 3;
822  ifRow.dwIndex = adapter->ipr.dwIndex;
823  if (GetIfEntry(&ifRow) != NO_ERROR)
824  ret = NRC_BRIDGE;
825  else
826  {
827  physAddrLen = min(ifRow.dwPhysAddrLen, 6);
828  if (physAddrLen > 0)
829  memcpy(astat->adapter_address, ifRow.bPhysAddr, physAddrLen);
830  /* doubt anyone cares, but why not.. */
831  if (ifRow.dwType == MIB_IF_TYPE_TOKENRING)
832  astat->adapter_type = 0xff;
833  else
834  astat->adapter_type = 0xfe; /* for Ethernet */
835  astat->max_sess_pkt_size = 0xffff;
836  astat->xmit_success = adapter->xmit_success;
837  astat->recv_success = adapter->recv_success;
838  ret = NRC_GOODRET;
839  }
840  }
841  else
842  ret = NetBTAstatRemote(adapter, ncb);
843  TRACE("returning 0x%02x\n", ret);
844  return ret;
845 }
846 
847 static UCHAR NetBTFindName(void *adapt, PNCB ncb)
848 {
849  NetBTAdapter *adapter = adapt;
850  UCHAR ret;
851  const NBNameCacheEntry *cacheEntry = NULL;
852  PFIND_NAME_HEADER foundName;
853 
854  TRACE("adapt %p, NCB %p\n", adapt, ncb);
855 
856  if (!adapter) return NRC_ENVNOTDEF;
857  if (!ncb) return NRC_INVADDRESS;
858  if (!ncb->ncb_buffer) return NRC_BADDR;
859  if (ncb->ncb_length < sizeof(FIND_NAME_HEADER)) return NRC_BUFLEN;
860 
861  foundName = (PFIND_NAME_HEADER)ncb->ncb_buffer;
862  memset(foundName, 0, sizeof(FIND_NAME_HEADER));
863 
864  ret = NetBTInternalFindName(adapter, ncb, &cacheEntry);
865  if (ret == NRC_GOODRET)
866  {
867  if (cacheEntry)
868  {
869  DWORD spaceFor = min((ncb->ncb_length - sizeof(FIND_NAME_HEADER)) /
870  sizeof(FIND_NAME_BUFFER), cacheEntry->numAddresses);
871  DWORD ndx;
872 
873  for (ndx = 0; ndx < spaceFor; ndx++)
874  {
875  PFIND_NAME_BUFFER findNameBuffer;
876 
877  findNameBuffer =
878  (PFIND_NAME_BUFFER)((PUCHAR)foundName +
879  sizeof(FIND_NAME_HEADER) + foundName->node_count *
880  sizeof(FIND_NAME_BUFFER));
881  memset(findNameBuffer->destination_addr, 0, 2);
882  memcpy(findNameBuffer->destination_addr + 2,
883  &adapter->ipr.dwAddr, sizeof(DWORD));
884  memset(findNameBuffer->source_addr, 0, 2);
885  memcpy(findNameBuffer->source_addr + 2,
886  &cacheEntry->addresses[ndx], sizeof(DWORD));
887  foundName->node_count++;
888  }
889  if (spaceFor < cacheEntry->numAddresses)
890  ret = NRC_BUFLEN;
891  }
892  else
893  ret = NRC_CMDTMO;
894  }
895  TRACE("returning 0x%02x\n", ret);
896  return ret;
897 }
898 
899 static UCHAR NetBTSessionReq(SOCKET fd, const UCHAR *calledName,
900  const UCHAR *callingName)
901 {
903  int r;
904  unsigned int len = 0;
905  DWORD bytesSent, bytesReceived, recvFlags = 0;
906  WSABUF wsaBuf;
907 
908  buffer[0] = NBSS_REQ;
909  buffer[1] = 0;
910 
911  len += NetBTNameEncode(calledName, &buffer[NBSS_HDRSIZE]);
912  len += NetBTNameEncode(callingName, &buffer[NBSS_HDRSIZE + len]);
913 
914  NBR_ADDWORD(&buffer[2], len);
915 
916  wsaBuf.len = len + NBSS_HDRSIZE;
917  wsaBuf.buf = (char*)buffer;
918 
919  r = WSASend(fd, &wsaBuf, 1, &bytesSent, 0, NULL, NULL);
920  if(r < 0 || bytesSent < len + NBSS_HDRSIZE)
921  {
922  ERR("send failed\n");
923  return NRC_SABORT;
924  }
925 
926  /* I've already set the recv timeout on this socket (if it supports it), so
927  * just block. Hopefully we'll always receive the session acknowledgement
928  * within one timeout.
929  */
930  wsaBuf.len = NBSS_HDRSIZE + 1;
931  r = WSARecv(fd, &wsaBuf, 1, &bytesReceived, &recvFlags, NULL, NULL);
932  if (r < 0 || bytesReceived < NBSS_HDRSIZE)
933  ret = NRC_SABORT;
934  else if (buffer[0] == NBSS_NACK)
935  {
936  if (r == NBSS_HDRSIZE + 1)
937  {
938  switch (buffer[NBSS_HDRSIZE])
939  {
941  ret = NRC_REMTFUL;
942  break;
943  default:
944  ret = NRC_NOCALL;
945  }
946  }
947  else
948  ret = NRC_NOCALL;
949  }
950  else if (buffer[0] == NBSS_RETARGET)
951  {
952  FIXME("Got a session retarget, can't deal\n");
953  ret = NRC_NOCALL;
954  }
955  else if (buffer[0] == NBSS_ACK)
956  ret = NRC_GOODRET;
957  else
958  ret = NRC_SYSTEM;
959 
960  TRACE("returning 0x%02x\n", ret);
961  return ret;
962 }
963 
964 static UCHAR NetBTCall(void *adapt, PNCB ncb, void **sess)
965 {
966  NetBTAdapter *adapter = adapt;
967  UCHAR ret;
968  const NBNameCacheEntry *cacheEntry = NULL;
969 
970  TRACE("adapt %p, ncb %p\n", adapt, ncb);
971 
972  if (!adapter) return NRC_ENVNOTDEF;
973  if (!ncb) return NRC_INVADDRESS;
974  if (!sess) return NRC_BADDR;
975 
976  ret = NetBTInternalFindName(adapter, ncb, &cacheEntry);
977  if (ret == NRC_GOODRET)
978  {
979  if (cacheEntry && cacheEntry->numAddresses > 0)
980  {
981  SOCKET fd;
982 
985  if (fd != INVALID_SOCKET)
986  {
987  DWORD timeout;
988  struct sockaddr_in sin;
989 
990  if (ncb->ncb_rto > 0)
991  {
992  timeout = ncb->ncb_rto * 500;
994  sizeof(timeout));
995  }
996  if (ncb->ncb_sto > 0)
997  {
998  timeout = ncb->ncb_sto * 500;
1000  sizeof(timeout));
1001  }
1002 
1003  memset(&sin, 0, sizeof(sin));
1004  memcpy(&sin.sin_addr, &cacheEntry->addresses[0],
1005  sizeof(sin.sin_addr));
1006  sin.sin_family = AF_INET;
1007  sin.sin_port = htons(PORT_NBSS);
1008  /* FIXME: use nonblocking mode for the socket, check the
1009  * cancel flag periodically
1010  */
1011  if (connect(fd, (struct sockaddr *)&sin, sizeof(sin))
1012  == SOCKET_ERROR)
1013  ret = NRC_CMDTMO;
1014  else
1015  {
1016  static const UCHAR fakedCalledName[] = "*SMBSERVER";
1017  const UCHAR *calledParty = cacheEntry->nbname[0] == '*'
1018  ? fakedCalledName : cacheEntry->nbname;
1019 
1020  ret = NetBTSessionReq(fd, calledParty, ncb->ncb_name);
1021  if (ret != NRC_GOODRET && calledParty[0] == '*')
1022  {
1023  FIXME("NBT session to \"*SMBSERVER\" refused,\n");
1024  FIXME("should try finding name using ASTAT\n");
1025  }
1026  }
1027  if (ret != NRC_GOODRET)
1028  closesocket(fd);
1029  else
1030  {
1031  NetBTSession *session = HeapAlloc(
1033 
1034  if (session)
1035  {
1036  session->fd = fd;
1037  InitializeCriticalSection(&session->cs);
1038  session->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": NetBTSession.cs");
1039  *sess = session;
1040  }
1041  else
1042  {
1043  ret = NRC_OSRESNOTAV;
1044  closesocket(fd);
1045  }
1046  }
1047  }
1048  else
1049  ret = NRC_OSRESNOTAV;
1050  }
1051  else
1052  ret = NRC_NAMERR;
1053  }
1054  TRACE("returning 0x%02x\n", ret);
1055  return ret;
1056 }
1057 
1058 /* Notice that I don't protect against multiple thread access to NetBTSend.
1059  * This is because I don't update any data in the adapter, and I only make a
1060  * single call to WSASend, which I assume to act atomically (not interleaving
1061  * data from other threads).
1062  * I don't lock, because I only depend on the fd being valid, and this won't be
1063  * true until a session setup is completed.
1064  */
1065 static UCHAR NetBTSend(void *adapt, void *sess, PNCB ncb)
1066 {
1067  NetBTAdapter *adapter = adapt;
1068  NetBTSession *session = sess;
1070  int r;
1071  WSABUF wsaBufs[2];
1072  DWORD bytesSent;
1073 
1074  TRACE("adapt %p, session %p, NCB %p\n", adapt, session, ncb);
1075 
1076  if (!adapter) return NRC_ENVNOTDEF;
1077  if (!ncb) return NRC_INVADDRESS;
1078  if (!ncb->ncb_buffer) return NRC_BADDR;
1079  if (!session) return NRC_SNUMOUT;
1080  if (session->fd == INVALID_SOCKET) return NRC_SNUMOUT;
1081 
1082  buffer[0] = NBSS_MSG;
1083  buffer[1] = 0;
1084  NBR_ADDWORD(&buffer[2], ncb->ncb_length);
1085 
1086  wsaBufs[0].len = NBSS_HDRSIZE;
1087  wsaBufs[0].buf = (char*)buffer;
1088  wsaBufs[1].len = ncb->ncb_length;
1089  wsaBufs[1].buf = (char*)ncb->ncb_buffer;
1090 
1091  r = WSASend(session->fd, wsaBufs, sizeof(wsaBufs) / sizeof(wsaBufs[0]),
1092  &bytesSent, 0, NULL, NULL);
1093  if (r == SOCKET_ERROR)
1094  {
1095  NetBIOSHangupSession(ncb);
1096  ret = NRC_SABORT;
1097  }
1098  else if (bytesSent < NBSS_HDRSIZE + ncb->ncb_length)
1099  {
1100  FIXME("Only sent %d bytes (of %d), hanging up session\n", bytesSent,
1101  NBSS_HDRSIZE + ncb->ncb_length);
1102  NetBIOSHangupSession(ncb);
1103  ret = NRC_SABORT;
1104  }
1105  else
1106  {
1107  ret = NRC_GOODRET;
1108  adapter->xmit_success++;
1109  }
1110  TRACE("returning 0x%02x\n", ret);
1111  return ret;
1112 }
1113 
1114 static UCHAR NetBTRecv(void *adapt, void *sess, PNCB ncb)
1115 {
1116  NetBTAdapter *adapter = adapt;
1117  NetBTSession *session = sess;
1119  int r;
1120  WSABUF wsaBufs[2];
1121  DWORD bufferCount, bytesReceived, flags;
1122 
1123  TRACE("adapt %p, session %p, NCB %p\n", adapt, session, ncb);
1124 
1125  if (!adapter) return NRC_ENVNOTDEF;
1126  if (!ncb) return NRC_BADDR;
1127  if (!ncb->ncb_buffer) return NRC_BADDR;
1128  if (!session) return NRC_SNUMOUT;
1129  if (session->fd == INVALID_SOCKET) return NRC_SNUMOUT;
1130 
1131  EnterCriticalSection(&session->cs);
1132  bufferCount = 0;
1133  if (session->bytesPending == 0)
1134  {
1135  bufferCount++;
1136  wsaBufs[0].len = NBSS_HDRSIZE;
1137  wsaBufs[0].buf = (char*)buffer;
1138  }
1139  wsaBufs[bufferCount].len = ncb->ncb_length;
1140  wsaBufs[bufferCount].buf = (char*)ncb->ncb_buffer;
1141  bufferCount++;
1142 
1143  flags = 0;
1144  /* FIXME: should poll a bit so I can check the cancel flag */
1145  r = WSARecv(session->fd, wsaBufs, bufferCount, &bytesReceived, &flags,
1146  NULL, NULL);
1148  {
1149  LeaveCriticalSection(&session->cs);
1150  ERR("Receive error, WSAGetLastError() returns %d\n", WSAGetLastError());
1151  NetBIOSHangupSession(ncb);
1152  ret = NRC_SABORT;
1153  }
1154  else if (NCB_CANCELLED(ncb))
1155  {
1156  LeaveCriticalSection(&session->cs);
1157  ret = NRC_CMDCAN;
1158  }
1159  else
1160  {
1161  if (bufferCount == 2)
1162  {
1163  if (buffer[0] == NBSS_KEEPALIVE)
1164  {
1165  LeaveCriticalSection(&session->cs);
1166  FIXME("Oops, received a session keepalive and lost my place\n");
1167  /* need to read another session header until we get a session
1168  * message header. */
1169  NetBIOSHangupSession(ncb);
1170  ret = NRC_SABORT;
1171  goto error;
1172  }
1173  else if (buffer[0] != NBSS_MSG)
1174  {
1175  LeaveCriticalSection(&session->cs);
1176  FIXME("Received unexpected session msg type %d\n", buffer[0]);
1177  NetBIOSHangupSession(ncb);
1178  ret = NRC_SABORT;
1179  goto error;
1180  }
1181  else
1182  {
1183  if (buffer[1] & NBSS_EXTENSION)
1184  {
1185  LeaveCriticalSection(&session->cs);
1186  FIXME("Received a message that's too long for my taste\n");
1187  NetBIOSHangupSession(ncb);
1188  ret = NRC_SABORT;
1189  goto error;
1190  }
1191  else
1192  {
1193  session->bytesPending = NBSS_HDRSIZE
1194  + NBR_GETWORD(&buffer[2]) - bytesReceived;
1195  ncb->ncb_length = bytesReceived - NBSS_HDRSIZE;
1196  LeaveCriticalSection(&session->cs);
1197  }
1198  }
1199  }
1200  else
1201  {
1202  if (bytesReceived < session->bytesPending)
1203  session->bytesPending -= bytesReceived;
1204  else
1205  session->bytesPending = 0;
1206  LeaveCriticalSection(&session->cs);
1207  ncb->ncb_length = bytesReceived;
1208  }
1209  if (session->bytesPending > 0)
1210  ret = NRC_INCOMP;
1211  else
1212  {
1213  ret = NRC_GOODRET;
1214  adapter->recv_success++;
1215  }
1216  }
1217 error:
1218  TRACE("returning 0x%02x\n", ret);
1219  return ret;
1220 }
1221 
1222 static UCHAR NetBTHangup(void *adapt, void *sess)
1223 {
1224  NetBTSession *session = sess;
1225 
1226  TRACE("adapt %p, session %p\n", adapt, session);
1227 
1228  if (!session) return NRC_SNUMOUT;
1229 
1230  /* I don't lock the session, because NetBTRecv knows not to decrement
1231  * past 0, so if a receive completes after this it should still deal.
1232  */
1233  closesocket(session->fd);
1234  session->fd = INVALID_SOCKET;
1235  session->bytesPending = 0;
1236  session->cs.DebugInfo->Spare[0] = 0;
1237  DeleteCriticalSection(&session->cs);
1238  HeapFree(GetProcessHeap(), 0, session);
1239 
1240  return NRC_GOODRET;
1241 }
1242 
1243 static void NetBTCleanupAdapter(void *adapt)
1244 {
1245  TRACE("adapt %p\n", adapt);
1246  if (adapt)
1247  {
1248  NetBTAdapter *adapter = adapt;
1249 
1250  if (adapter->nameCache)
1251  NBNameCacheDestroy(adapter->nameCache);
1252  HeapFree(GetProcessHeap(), 0, adapt);
1253  }
1254 }
1255 
1256 static void NetBTCleanup(void)
1257 {
1258  TRACE("\n");
1259  if (gNameCache)
1260  {
1262  gNameCache = NULL;
1263  }
1264 }
1265 
1267 {
1268  UCHAR ret;
1269  NetBTAdapter *adapter;
1270 
1271  if (!ipRow) return NRC_BADDR;
1272 
1273  adapter = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NetBTAdapter));
1274  if (adapter)
1275  {
1276  adapter->ipr = *ipRow;
1277  if (!NetBIOSRegisterAdapter(gTransportID, ipRow->dwIndex, adapter))
1278  {
1279  NetBTCleanupAdapter(adapter);
1280  ret = NRC_SYSTEM;
1281  }
1282  else
1283  ret = NRC_GOODRET;
1284  }
1285  else
1286  ret = NRC_OSRESNOTAV;
1287  return ret;
1288 }
1289 
1290 /* Callback for NetBIOS adapter enumeration. Assumes closure is a pointer to
1291  * a MIB_IPADDRTABLE containing all the IP adapters needed to be added to the
1292  * NetBIOS adapter table. For each callback, checks if the passed-in adapt
1293  * has an entry in the table; if so, this adapter was enumerated previously,
1294  * and it's enabled. As a flag, the table's dwAddr entry is changed to
1295  * INADDR_LOOPBACK, since this is an invalid address for a NetBT adapter.
1296  * The NetBTEnum function will add any remaining adapters from the
1297  * MIB_IPADDRTABLE to the NetBIOS adapter table.
1298  */
1299 static BOOL NetBTEnumCallback(UCHAR totalLANAs, UCHAR lanaIndex,
1300  ULONG transport, const NetBIOSAdapterImpl *data, void *closure)
1301 {
1302  BOOL ret;
1303  PMIB_IPADDRTABLE table = closure;
1304 
1305  if (table && data)
1306  {
1307  DWORD ndx;
1308 
1309  ret = FALSE;
1310  for (ndx = 0; !ret && ndx < table->dwNumEntries; ndx++)
1311  {
1312  const NetBTAdapter *adapter = data->data;
1313 
1314  if (table->table[ndx].dwIndex == adapter->ipr.dwIndex)
1315  {
1316  NetBIOSEnableAdapter(data->lana);
1317  table->table[ndx].dwAddr = INADDR_LOOPBACK;
1318  ret = TRUE;
1319  }
1320  }
1321  }
1322  else
1323  ret = FALSE;
1324  return ret;
1325 }
1326 
1327 /* Enumerates adapters by:
1328  * - retrieving the IP address table for the local machine
1329  * - eliminating loopback addresses from the table
1330  * - eliminating redundant addresses, that is, multiple addresses on the same
1331  * subnet
1332  * Calls NetBIOSEnumAdapters, passing the resulting table as the callback
1333  * data. The callback reenables each adapter that's already in the NetBIOS
1334  * table. After NetBIOSEnumAdapters returns, this function adds any remaining
1335  * adapters to the NetBIOS table.
1336  */
1337 static UCHAR NetBTEnum(void)
1338 {
1339  UCHAR ret;
1340  DWORD size = 0;
1341 
1342  TRACE("\n");
1343 
1345  {
1346  PMIB_IPADDRTABLE ipAddrs, coalesceTable = NULL;
1347  DWORD numIPAddrs = (size - sizeof(MIB_IPADDRTABLE)) /
1348  sizeof(MIB_IPADDRROW) + 1;
1349 
1351  if (ipAddrs)
1352  coalesceTable = HeapAlloc(GetProcessHeap(),
1354  (min(numIPAddrs, MAX_LANA + 1) - 1) * sizeof(MIB_IPADDRROW));
1355  if (ipAddrs && coalesceTable)
1356  {
1357  if (GetIpAddrTable(ipAddrs, &size, FALSE) == ERROR_SUCCESS)
1358  {
1359  DWORD ndx;
1360 
1361  for (ndx = 0; ndx < ipAddrs->dwNumEntries; ndx++)
1362  {
1363  if ((ipAddrs->table[ndx].dwAddr &
1364  ipAddrs->table[ndx].dwMask) !=
1366  {
1367  BOOL newNetwork = TRUE;
1368  DWORD innerIndex;
1369 
1370  /* make sure we don't have more than one entry
1371  * for a subnet */
1372  for (innerIndex = 0; newNetwork &&
1373  innerIndex < coalesceTable->dwNumEntries; innerIndex++)
1374  if ((ipAddrs->table[ndx].dwAddr &
1375  ipAddrs->table[ndx].dwMask) ==
1376  (coalesceTable->table[innerIndex].dwAddr
1377  & coalesceTable->table[innerIndex].dwMask))
1378  newNetwork = FALSE;
1379 
1380  if (newNetwork)
1381  memcpy(&coalesceTable->table[
1382  coalesceTable->dwNumEntries++],
1383  &ipAddrs->table[ndx], sizeof(MIB_IPADDRROW));
1384  }
1385  }
1386 
1388  coalesceTable);
1389  ret = NRC_GOODRET;
1390  for (ndx = 0; ret == NRC_GOODRET &&
1391  ndx < coalesceTable->dwNumEntries; ndx++)
1392  if (coalesceTable->table[ndx].dwAddr != INADDR_LOOPBACK)
1393  ret = NetBTRegisterAdapter(&coalesceTable->table[ndx]);
1394  }
1395  else
1396  ret = NRC_SYSTEM;
1397  HeapFree(GetProcessHeap(), 0, ipAddrs);
1398  HeapFree(GetProcessHeap(), 0, coalesceTable);
1399  }
1400  else
1401  ret = NRC_OSRESNOTAV;
1402  }
1403  else
1404  ret = NRC_SYSTEM;
1405  TRACE("returning 0x%02x\n", ret);
1406  return ret;
1407 }
1408 
1409 static const WCHAR VxD_MSTCPW[] = { 'S','Y','S','T','E','M','\\','C','u','r',
1410  'r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','S','e','r','v',
1411  'i','c','e','s','\\','V','x','D','\\','M','S','T','C','P','\0' };
1412 static const WCHAR NetBT_ParametersW[] = { 'S','Y','S','T','E','M','\\','C','u',
1413  'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','S','e','r',
1414  'v','i','c','e','s','\\','N','e','t','B','T','\\','P','a','r','a','m','e','t',
1415  'e','r','s','\0' };
1416 static const WCHAR EnableDNSW[] = { 'E','n','a','b','l','e','D','N','S','\0' };
1417 static const WCHAR BcastNameQueryCountW[] = { 'B','c','a','s','t','N','a','m',
1418  'e','Q','u','e','r','y','C','o','u','n','t','\0' };
1419 static const WCHAR BcastNameQueryTimeoutW[] = { 'B','c','a','s','t','N','a','m',
1420  'e','Q','u','e','r','y','T','i','m','e','o','u','t','\0' };
1421 static const WCHAR NameSrvQueryCountW[] = { 'N','a','m','e','S','r','v',
1422  'Q','u','e','r','y','C','o','u','n','t','\0' };
1423 static const WCHAR NameSrvQueryTimeoutW[] = { 'N','a','m','e','S','r','v',
1424  'Q','u','e','r','y','T','i','m','e','o','u','t','\0' };
1425 static const WCHAR ScopeIDW[] = { 'S','c','o','p','e','I','D','\0' };
1426 static const WCHAR CacheTimeoutW[] = { 'C','a','c','h','e','T','i','m','e','o',
1427  'u','t','\0' };
1428 static const WCHAR Config_NetworkW[] = { 'S','o','f','t','w','a','r','e','\\',
1429  'W','i','n','e','\\','N','e','t','w','o','r','k','\0' };
1430 
1431 /* Initializes global variables and registers the NetBT transport */
1432 void NetBTInit(void)
1433 {
1434  HKEY hKey;
1435  NetBIOSTransport transport;
1436  LONG ret;
1437 
1438  TRACE("\n");
1439 
1440  gEnableDNS = TRUE;
1445  gNumWINSServers = 0;
1446  memset(gWINSServers, 0, sizeof(gWINSServers));
1447  gScopeID[0] = '\0';
1449 
1450  /* Try to open the Win9x NetBT configuration key */
1452  /* If that fails, try the WinNT NetBT configuration key */
1453  if (ret != ERROR_SUCCESS)
1455  &hKey);
1456  if (ret == ERROR_SUCCESS)
1457  {
1458  DWORD dword, size;
1459 
1460  size = sizeof(dword);
1461  if (RegQueryValueExW(hKey, EnableDNSW, NULL, NULL,
1462  (LPBYTE)&dword, &size) == ERROR_SUCCESS)
1463  gEnableDNS = dword;
1464  size = sizeof(dword);
1466  (LPBYTE)&dword, &size) == ERROR_SUCCESS && dword >= MIN_QUERIES
1467  && dword <= MAX_QUERIES)
1468  gBCastQueries = dword;
1469  size = sizeof(dword);
1471  (LPBYTE)&dword, &size) == ERROR_SUCCESS && dword >= MIN_QUERY_TIMEOUT)
1472  gBCastQueryTimeout = dword;
1473  size = sizeof(dword);
1475  (LPBYTE)&dword, &size) == ERROR_SUCCESS && dword >= MIN_QUERIES
1476  && dword <= MAX_QUERIES)
1477  gWINSQueries = dword;
1478  size = sizeof(dword);
1480  (LPBYTE)&dword, &size) == ERROR_SUCCESS && dword >= MIN_QUERY_TIMEOUT)
1481  gWINSQueryTimeout = dword;
1482  size = sizeof(gScopeID) - 1;
1483  if (RegQueryValueExW(hKey, ScopeIDW, NULL, NULL, (LPBYTE)gScopeID + 1, &size)
1484  == ERROR_SUCCESS)
1485  {
1486  /* convert into L2-encoded version, suitable for use by
1487  NetBTNameEncode */
1488  char *ptr, *lenPtr;
1489 
1490  for (ptr = gScopeID + 1, lenPtr = gScopeID; ptr - gScopeID < sizeof(gScopeID) && *ptr; ++ptr)
1491  {
1492  if (*ptr == '.')
1493  {
1494  lenPtr = ptr;
1495  *lenPtr = 0;
1496  }
1497  else
1498  {
1499  ++*lenPtr;
1500  }
1501  }
1502  }
1504  (LPBYTE)&dword, &size) == ERROR_SUCCESS && dword >= MIN_CACHE_TIMEOUT)
1505  gCacheTimeout = dword;
1506  RegCloseKey(hKey);
1507  }
1508  /* WINE-specific NetBT registry settings. Because our adapter naming is
1509  * different than MS', we can't do per-adapter WINS configuration in the
1510  * same place. Just do a global WINS configuration instead.
1511  */
1512  /* @@ Wine registry key: HKCU\Software\Wine\Network */
1514  {
1515  static const char *nsValueNames[] = { "WinsServer", "BackupWinsServer" };
1516  char nsString[16];
1517  DWORD size, ndx;
1518 
1519  for (ndx = 0; ndx < sizeof(nsValueNames) / sizeof(nsValueNames[0]);
1520  ndx++)
1521  {
1522  size = sizeof(nsString) / sizeof(char);
1523  if (RegQueryValueExA(hKey, nsValueNames[ndx], NULL, NULL,
1524  (LPBYTE)nsString, &size) == ERROR_SUCCESS)
1525  {
1526  unsigned long addr = inet_addr(nsString);
1527 
1530  }
1531  }
1532  RegCloseKey(hKey);
1533  }
1534 
1535  transport.enumerate = NetBTEnum;
1536  transport.astat = NetBTAstat;
1537  transport.findName = NetBTFindName;
1538  transport.call = NetBTCall;
1539  transport.send = NetBTSend;
1540  transport.recv = NetBTRecv;
1541  transport.hangup = NetBTHangup;
1542  transport.cleanupAdapter = NetBTCleanupAdapter;
1543  transport.cleanup = NetBTCleanup;
1544  memcpy(&gTransportID, TRANSPORT_NBT, sizeof(ULONG));
1546 }
static DWORD gWINSQueryTimeout
Definition: nbt.c:146
Definition: winsock.h:66
struct _NetBTAdapter NetBTAdapter
#define SOCKET_ERROR
Definition: winsock.h:333
#define SIMPLE_NAME_QUERY_PKT_SIZE
Definition: nbt.c:99
#define NRC_CMDTMO
Definition: nb30.h:55
struct _MIB_IPADDRTABLE MIB_IPADDRTABLE
#define NBSS_ERR_INSUFFICIENT_RESOURCES
Definition: nbt.c:121
LONG WINAPI RegQueryValueExA(_In_ HKEY hkeyorg, _In_ LPCSTR name, _In_ LPDWORD reserved, _Out_opt_ LPDWORD type, _Out_opt_ LPBYTE data, _Inout_opt_ LPDWORD count)
Definition: reg.c:4041
#define BCAST_QUERIES
Definition: nbt.c:90
#define BCAST_QUERY_TIMEOUT
Definition: nbt.c:91
NetBIOSFindName findName
Definition: netbios.h:155
static DWORD gBCastQueryTimeout
Definition: nbt.c:144
#define TRUE
Definition: types.h:120
WINE_DEFAULT_DEBUG_CHANNEL(netbios)
NetBIOSAstat astat
Definition: netbios.h:154
#define WSA_FLAG_OVERLAPPED
Definition: winsock2.h:466
#define NRC_GOODRET
Definition: nb30.h:52
SOCKET fd
Definition: nbt.c:128
NBNameCacheEntry * cacheEntry
Definition: nbt.c:383
UCHAR adapter_type
Definition: nb30.h:101
#define inet_addr(cp)
Definition: inet.h:98
#define ERROR_SUCCESS
Definition: deptool.c:10
#define DWORD_PTR
Definition: treelist.c:76
#define error(str)
Definition: mkdosfs.c:1605
#define NBNS_CLASS_INTERNET
Definition: nbt.c:103
struct _NetBTNodeQueryData NetBTNodeQueryData
DWORD dwType
Definition: ifmib.h:39
#define NBSS_MSG
Definition: nbt.c:111
UCHAR ncb_rto
Definition: nb30.h:157
#define htonl(x)
Definition: module.h:212
#define NBNS_RESPONSE_AND_QUERY
Definition: nbt.c:106
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
#define KEY_READ
Definition: nt_native.h:1023
WORD max_sess_pkt_size
Definition: nb30.h:123
static UCHAR NetBTinetResolve(const UCHAR name[NCBNAMSZ], NBNameCacheEntry **cacheEntry)
Definition: nbt.c:509
static BOOL NetBTFindNameAnswerCallback(void *pVoid, WORD answerCount, WORD answerIndex, PUCHAR rData, WORD rLen)
Definition: nbt.c:392
UCHAR ncb_callname[NCBNAMSZ]
Definition: nb30.h:155
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
#define HKEY_CURRENT_USER
Definition: winreg.h:11
#define WINS_QUERIES
Definition: nbt.c:92
unsigned char * PUCHAR
Definition: retypes.h:3
char CHAR
Definition: xmlstorage.h:175
static UCHAR NetBTFindName(void *adapt, PNCB ncb)
Definition: nbt.c:847
#define NBSS_ACK
Definition: nbt.c:113
char * host
Definition: whois.c:55
Definition: nb30.h:148
UCHAR adapter_address[6]
Definition: nb30.h:98
SOCKET WSAAPI WSASocketA(IN INT af, IN INT type, IN INT protocol, IN LPWSAPROTOCOL_INFOA lpProtocolInfo, IN GROUP g, IN DWORD dwFlags)
Definition: socklife.c:444
static struct NBNameCache * gNameCache
Definition: nbt.c:151
struct _NetBTSession NetBTSession
#define MAX_LANA
Definition: nb30.h:8
#define NBNS_RESPONSE_AND_OPCODE
Definition: nbt.c:105
#define WSAEWOULDBLOCK
Definition: winerror.h:1948
DWORD xmit_success
Definition: nbt.c:137
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:445
#define DEREGISTERED
Definition: nb30.h:14
BOOL gotResponse
Definition: nbt.c:677
#define NBNS_REPLYCODE
Definition: nbt.c:107
void NetBIOSEnableAdapter(UCHAR lana)
Definition: netbios.c:231
GLuint buffer
Definition: glext.h:5915
#define NBSS_HDRSIZE
Definition: nbt.c:109
static int fd
Definition: io.c:51
Definition: dhcpd.h:245
BOOL NBNameCacheAddEntry(struct NBNameCache *cache, NBNameCacheEntry *entry)
Definition: nbnamecache.c:111
LONGLONG xid
Definition: nfs41_driver.c:106
#define MAX_QUERIES
Definition: nbt.c:87
struct NBNameCache * nameCache
Definition: nbt.c:136
#define SOL_SOCKET
Definition: winsock.h:398
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
#define FD_ZERO(set)
Definition: winsock.h:96
_Check_return_ _CRTIMP int __cdecl isalnum(_In_ int _C)
#define FD_SET(fd, set)
Definition: winsock.h:89
#define NO_ERROR
Definition: dderror.h:5
#define BOOL
Definition: nt_native.h:43
INT WSAAPI connect(IN SOCKET s, IN CONST struct sockaddr *name, IN INT namelen)
Definition: sockctrl.c:23
u32_t s_addr
Definition: inet.h:45
#define DWORD
Definition: nt_native.h:44
#define MIN_QUERY_TIMEOUT
Definition: nbt.c:88
struct NBNameCache * NBNameCacheCreate(HANDLE heap, DWORD entryExpireTimeMS)
Definition: nbnamecache.c:92
GLbitfield GLuint64 timeout
Definition: glext.h:7164
NetBIOSHangup hangup
Definition: netbios.h:159
static const WCHAR VxD_MSTCPW[]
Definition: nbt.c:1409
void NetBIOSEnumAdapters(ULONG transport, NetBIOSEnumAdaptersCallback cb, void *closure)
Definition: netbios.c:296
#define PORT_NBSS
Definition: nbt.c:77
static DWORD gWINSQueries
Definition: nbt.c:145
static UCHAR NetBTNameWaitLoop(const NetBTAdapter *adapter, SOCKET fd, const NCB *ncb, DWORD sendTo, BOOL broadcast, DWORD timeout, DWORD maxQueries, NBNameCacheEntry **cacheEntry)
Definition: nbt.c:433
static UCHAR NetBTSend(void *adapt, void *sess, PNCB ncb)
Definition: nbt.c:1065
static const WCHAR NetBT_ParametersW[]
Definition: nbt.c:1412
static UCHAR NetBTHangup(void *adapt, void *sess)
Definition: nbt.c:1222
#define GROUP_NAME
Definition: nb30.h:10
#define WINS_QUERY_TIMEOUT
Definition: nbt.c:93
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define NRC_INCOMP
Definition: nb30.h:56
#define NRC_ENVNOTDEF
Definition: nb30.h:80
#define NRC_SYSTEM
Definition: nb30.h:89
LONG WINAPI RegCloseKey(HKEY hKey)
Definition: reg.c:423
struct _FIND_NAME_HEADER * PFIND_NAME_HEADER
unsigned char * LPBYTE
Definition: typedefs.h:52
#define NBSS_KEEPALIVE
Definition: nbt.c:116
#define closesocket
Definition: main.c:39
DWORD bytesPending
Definition: nbt.c:129
unsigned int BOOL
Definition: ntddk_ex.h:94
#define CACHE_TIMEOUT
Definition: nbt.c:96
DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder)
long LONG
Definition: pedump.c:60
INT WSAAPI select(IN INT s, IN OUT LPFD_SET readfds, IN OUT LPFD_SET writefds, IN OUT LPFD_SET exceptfds, IN CONST struct timeval *timeout)
Definition: select.c:41
static UCHAR NetBTAstatRemote(NetBTAdapter *adapter, PNCB ncb)
Definition: nbt.c:738
time_t now
Definition: finger.c:65
#define SO_BROADCAST
Definition: winsock.h:183
static const WCHAR CacheTimeoutW[]
Definition: nbt.c:1426
LONG WINAPI RegOpenKeyW(HKEY hKey, LPCWSTR lpSubKey, PHKEY phkResult)
Definition: reg.c:3311
static UCHAR NetBTWaitForNameResponse(const NetBTAdapter *adapter, SOCKET fd, DWORD waitUntil, NetBTAnswerCallback answerCallback, void *data)
Definition: nbt.c:281
#define MAX_DOMAIN_NAME_LEN
Definition: iptypes.h:31
#define FIXME(fmt,...)
Definition: debug.h:110
INT WSAAPI WSARecvFrom(IN SOCKET s, IN OUT LPWSABUF lpBuffers, IN DWORD dwBufferCount, OUT LPDWORD lpNumberOfBytesRecvd, IN OUT LPDWORD lpFlags, OUT LPSOCKADDR lpFrom, IN OUT LPINT lpFromlen, IN LPWSAOVERLAPPED lpOverlapped, IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
Definition: recv.c:254
INT WSAAPI setsockopt(IN SOCKET s, IN INT level, IN INT optname, IN CONST CHAR FAR *optval, IN INT optlen)
Definition: sockctrl.c:421
static PVOID ptr
Definition: dispmode.c:27
NetBIOSSend send
Definition: netbios.h:157
UCHAR nbname[NCBNAMSZ]
Definition: nbnamecache.h:35
#define NRC_SABORT
Definition: nb30.h:72
struct _ADAPTER_STATUS * PADAPTER_STATUS
UCHAR name[NCBNAMSZ]
Definition: nbnamecache.h:34
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
Definition: synch.c:697
smooth NULL
Definition: ftsmooth.c:416
NetBIOSCleanupAdapter cleanupAdapter
Definition: netbios.h:160
#define NCB_CANCELLED(pncb)
Definition: netbios.h:129
WORD name_count
Definition: nb30.h:124
NetBIOSRecv recv
Definition: netbios.h:158
#define PF_INET
Definition: winsock.h:373
#define NCBNAMSZ
Definition: nb30.h:7
#define isdigit(c)
Definition: acclib.h:68
static UCHAR NetBTAstat(void *adapt, PNCB ncb)
Definition: nbt.c:802
#define inet_ntoa(addr)
Definition: inet.h:100
struct _NetBTNameQueryData NetBTNameQueryData
NetBIOSCall call
Definition: netbios.h:156
static int gNumWINSServers
Definition: nbt.c:148
PHOSTENT WSAAPI gethostbyname(IN const char FAR *name)
Definition: getxbyxx.c:221
#define SO_RCVTIMEO
Definition: winsock.h:193
#define TRACE(s)
Definition: solgame.cpp:4
INT WSAAPI WSAGetLastError(VOID)
Definition: dllmain.c:112
static DWORD gBCastQueries
Definition: nbt.c:143
GLsizeiptr size
Definition: glext.h:5919
#define GetProcessHeap()
Definition: compat.h:395
DWORD dwBCastAddr
Definition: ipmib.h:39
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
#define INVALID_SOCKET
Definition: winsock.h:332
#define NBSS_EXTENSION
Definition: nbt.c:123
void NBNameCacheDestroy(struct NBNameCache *cache)
Definition: nbnamecache.c:176
LONG WINAPI RegQueryValueExW(_In_ HKEY hkeyorg, _In_ LPCWSTR name, _In_ LPDWORD reserved, _In_ LPDWORD type, _In_ LPBYTE data, _In_ LPDWORD count)
Definition: reg.c:4134
UCHAR bPhysAddr[MAXLEN_PHYSADDR]
Definition: ifmib.h:43
__wchar_t WCHAR
Definition: xmlstorage.h:180
void WINAPI DeleteCriticalSection(PCRITICAL_SECTION)
WORD ncb_length
Definition: nb30.h:154
#define MAX_SCOPE_ID_LEN
Definition: iptypes.h:32
#define NBSS_REQ
Definition: nbt.c:112
Definition: tcpip.h:125
ULONG len
Definition: ws2def.h:519
static UCHAR NetBTEnum(void)
Definition: nbt.c:1337
unsigned short WORD
Definition: ntddk_ex.h:93
BOOL(* NetBTAnswerCallback)(void *data, WORD answerCount, WORD answerIndex, PUCHAR rData, WORD rdLength)
Definition: nbt.c:269
#define for
Definition: utility.h:88
unsigned long DWORD
Definition: ntddk_ex.h:95
INT WSAAPI WSASendTo(IN SOCKET s, IN LPWSABUF lpBuffers, IN DWORD dwBufferCount, OUT LPDWORD lpNumberOfBytesSent, IN DWORD dwFlags, IN CONST struct sockaddr *lpTo, IN INT iToLen, IN LPWSAOVERLAPPED lpOverlapped, IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
Definition: send.c:247
#define NRC_CMDCAN
Definition: nb30.h:61
static const WCHAR NameSrvQueryCountW[]
Definition: nbt.c:1421
static ULONG gTransportID
Definition: nbt.c:141
#define MIN_CACHE_TIMEOUT
Definition: nbt.c:95
void NetBTInit(void)
Definition: nbt.c:1432
#define MIN_QUERIES
Definition: nbt.c:86
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
PCRITICAL_SECTION_DEBUG DebugInfo
Definition: winbase.h:859
static BOOL NetBTEnumCallback(UCHAR totalLANAs, UCHAR lanaIndex, ULONG transport, const NetBIOSAdapterImpl *data, void *closure)
Definition: nbt.c:1299
static const WCHAR EnableDNSW[]
Definition: nbt.c:1416
GLbitfield flags
Definition: glext.h:7161
static DWORD NetBTNameReq(const UCHAR name[NCBNAMSZ], WORD xid, WORD qtype, BOOL broadcast, UCHAR *buffer, int len)
Definition: nbt.c:191
#define MIB_IF_TYPE_TOKENRING
Definition: ipifcons.h:224
#define NRC_REMTFUL
Definition: nb30.h:66
unsigned char UCHAR
Definition: xmlstorage.h:181
#define NRC_SNUMOUT
Definition: nb30.h:58
int ret
#define INADDR_NONE
Definition: nbt.c:80
static UCHAR NetBTInternalFindName(NetBTAdapter *adapter, PNCB ncb, const NBNameCacheEntry **cacheEntry)
Definition: nbt.c:593
static char gScopeID[MAX_SCOPE_ID_LEN]
Definition: nbt.c:149
GLenum const GLvoid * addr
Definition: glext.h:9621
BOOL NetBIOSRegisterTransport(ULONG id, NetBIOSTransport *transport)
Definition: netbios.c:131
#define NRC_NAMERR
Definition: nb30.h:71
static const WCHAR BcastNameQueryCountW[]
Definition: nbt.c:1417
#define IN_CLASSA_NET
Definition: winsock.h:298
#define NRC_NOWILD
Definition: nb30.h:69
DWORD dwPhysAddrLen
Definition: ifmib.h:42
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
static INT adapt(INT delta, INT numpoints, BOOL firsttime)
Definition: IdnToAscii.c:20
static const WCHAR NameSrvQueryTimeoutW[]
Definition: nbt.c:1423
GLenum src
Definition: glext.h:6340
void NetBIOSHangupSession(const NCB *ncb)
Definition: netbios.c:664
#define REGISTERING
Definition: nb30.h:12
UCHAR destination_addr[6]
Definition: nb30.h:130
#define NRC_BRIDGE
Definition: nb30.h:76
CHAR FAR * buf
Definition: ws2def.h:520
#define TRANSPORT_NBT
Definition: netbios.h:173
DWORD dwMask
Definition: ipmib.h:38
#define NRC_BUFLEN
Definition: nb30.h:53
#define ERR(fmt,...)
Definition: debug.h:109
#define PORT_NBNS
Definition: nbt.c:75
DWORD addresses[1]
Definition: nbnamecache.h:37
INT WSAAPI WSASend(IN SOCKET s, IN LPWSABUF lpBuffers, IN DWORD dwBufferCount, OUT LPDWORD lpNumberOfBytesSent, IN DWORD dwFlags, IN LPWSAOVERLAPPED lpOverlapped, IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
Definition: send.c:145
NetBIOSCleanup cleanup
Definition: netbios.h:161
static UCHAR NetBTStoreCacheEntry(struct NBNameCache **nameCache, NBNameCacheEntry *cacheEntry)
Definition: nbt.c:480
static DWORD gCacheTimeout
Definition: nbt.c:150
INT WSAAPI WSARecv(IN SOCKET s, IN OUT LPWSABUF lpBuffers, IN DWORD dwBufferCount, OUT LPDWORD lpNumberOfBytesRecvd, IN OUT LPDWORD lpFlags, IN LPWSAOVERLAPPED lpOverlapped, IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
Definition: recv.c:155
struct _FIND_NAME_HEADER FIND_NAME_HEADER
static UCHAR NetBTRegisterAdapter(const MIB_IPADDRROW *ipRow)
Definition: nbt.c:1266
struct _MIB_IPADDRROW MIB_IPADDRROW
static UCHAR NetBTCall(void *adapt, PNCB ncb, void **sess)
Definition: nbt.c:964
DWORD recv_success
Definition: nbt.c:138
#define NBSS_RETARGET
Definition: nbt.c:115
DWORD recv_success
Definition: nb30.h:109
DWORD dwNumEntries
Definition: ipmib.h:47
PUCHAR ncb_buffer
Definition: nb30.h:153
#define NRC_BADDR
Definition: nb30.h:57
CRITICAL_SECTION cs
Definition: nbt.c:127
GLenum GLenum dst
Definition: glext.h:6340
BOOL NetBIOSRegisterAdapter(ULONG transport, DWORD ifIndex, void *data)
Definition: netbios.c:175
static UCHAR NetBTRecv(void *adapt, void *sess, PNCB ncb)
Definition: nbt.c:1114
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:254
static const WCHAR Config_NetworkW[]
Definition: nbt.c:1428
DWORD WINAPI GetIfEntry(PMIB_IFROW pIfRow)
PADAPTER_STATUS astat
Definition: nbt.c:678
#define min(a, b)
Definition: monoChain.cc:55
UCHAR rev_major
Definition: nb30.h:99
#define HEAP_ZERO_MEMORY
Definition: compat.h:123
static BOOL gEnableDNS
Definition: nbt.c:142
NetBIOSEnum enumerate
Definition: netbios.h:153
#define NBNS_HEADER_SIZE
Definition: nbt.c:104
#define NBR_GETWORD(p)
Definition: nbt.c:84
IF_INDEX dwIndex
Definition: ipmib.h:37
UCHAR ncb_name[NCBNAMSZ]
Definition: nb30.h:156
static void NetBTCleanupAdapter(void *adapt)
Definition: nbt.c:1243
#define MAX_WINS_SERVERS
Definition: nbt.c:94
#define NBNS_TYPE_NBSTAT
Definition: nbt.c:102
#define NBNS_TYPE_NB
Definition: nbt.c:101
#define SO_SNDTIMEO
Definition: winsock.h:192
#define NRC_NOCALL
Definition: nb30.h:68
Definition: name.c:36
WORD node_count
Definition: nb30.h:135
#define NRC_INVADDRESS
Definition: nb30.h:85
unsigned int ULONG
Definition: retypes.h:1
#define AF_INET
Definition: tcpip.h:117
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3381
#define INADDR_LOOPBACK
Definition: winsock.h:312
struct _FIND_NAME_BUFFER * PFIND_NAME_BUFFER
#define NBSS_NACK
Definition: nbt.c:114
const NBNameCacheEntry * NBNameCacheFindEntry(struct NBNameCache *cache, const UCHAR name[NCBNAMSZ])
Definition: nbnamecache.c:151
UCHAR source_addr[6]
Definition: nb30.h:131
#define NRC_OSRESNOTAV
Definition: nb30.h:81
DWORD dwAddr
Definition: ipmib.h:36
UINT_PTR SOCKET
Definition: winsock.h:47
DWORD dwIndex
Definition: ifmib.h:38
data1 newNetwork
Definition: tftpd.cpp:50
#define DUPLICATE
Definition: nb30.h:15
static int NetBTSendNameQuery(SOCKET fd, const UCHAR name[NCBNAMSZ], WORD xid, WORD qtype, DWORD destAddr, BOOL broadcast)
Definition: nbt.c:227
_STLP_DECLSPEC complex< float > _STLP_CALL sin(const complex< float > &)
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
#define SOCK_STREAM
Definition: tcpip.h:118
static int NetBTNameEncode(const UCHAR *p, UCHAR *buffer)
Definition: nbt.c:158
GLfloat GLfloat p
Definition: glext.h:8902
#define htons(x)
Definition: module.h:213
static UCHAR NetBTSessionReq(SOCKET fd, const UCHAR *calledName, const UCHAR *callingName)
Definition: nbt.c:899
static const WCHAR ScopeIDW[]
Definition: nbt.c:1425
#define SOCK_DGRAM
Definition: winsock.h:336
static const WCHAR BcastNameQueryTimeoutW[]
Definition: nbt.c:1419
#define memset(x, y, z)
Definition: compat.h:39
static DWORD gWINSServers[MAX_WINS_SERVERS]
Definition: nbt.c:147
static void NetBTCleanup(void)
Definition: nbt.c:1256
#define HeapFree(x, y, z)
Definition: compat.h:394
MIB_IPADDRROW table[1]
Definition: ipmib.h:48
#define REGISTERED
Definition: nb30.h:13
static BOOL NetBTNodeStatusAnswerCallback(void *pVoid, WORD answerCount, WORD answerIndex, PUCHAR rData, WORD rLen)
Definition: nbt.c:686
UCHAR ncb_sto
Definition: nb30.h:158
#define NBR_ADDWORD(p, word)
Definition: nbt.c:83
DWORD xmit_success
Definition: nb30.h:108
DWORD_PTR Spare[8/sizeof(DWORD_PTR)]
Definition: winbase.h:852
MIB_IPADDRROW ipr
Definition: nbt.c:134
WORD nameQueryXID
Definition: nbt.c:135
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
#define ERROR_INSUFFICIENT_BUFFER
Definition: dderror.h:10