Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

360 lines
10 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. ntos\tdi\isn\fwd\netbios.c
  5. Abstract:
  6. Netbios packet processing
  7. Author:
  8. Vadim Eydelman
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. LIST_ENTRY NetbiosQueue;
  13. KSPIN_LOCK NetbiosQueueLock;
  14. WORK_QUEUE_ITEM NetbiosWorker;
  15. BOOLEAN NetbiosWorkerScheduled=FALSE;
  16. ULONG NetbiosPacketsQuota;
  17. ULONG MaxNetbiosPacketsQueued = DEF_MAX_NETBIOS_PACKETS_QUEUED;
  18. /*++
  19. *******************************************************************
  20. P r o c e s s N e t b i o s Q u e u e
  21. Routine Description:
  22. Process packets in the netbios broadcast queue (sends them on
  23. all interfaces in sequence)
  24. Arguments:
  25. Context - unused
  26. Return Value:
  27. None
  28. *******************************************************************
  29. --*/
  30. VOID
  31. ProcessNetbiosQueue (
  32. PVOID Context
  33. ) {
  34. KIRQL oldIRQL;
  35. LIST_ENTRY tempQueue;
  36. KeAcquireSpinLock (&NetbiosQueueLock, &oldIRQL);
  37. // Check if there is something in the queue
  38. if (!IsListEmpty (&NetbiosQueue)) {
  39. // Move the queue to local variable
  40. InsertHeadList (&NetbiosQueue, &tempQueue);
  41. RemoveEntryList (&NetbiosQueue);
  42. InitializeListHead (&NetbiosQueue);
  43. KeReleaseSpinLock (&NetbiosQueueLock, oldIRQL);
  44. do {
  45. PLIST_ENTRY cur;
  46. PPACKET_TAG pktTag;
  47. cur = RemoveHeadList (&tempQueue);
  48. pktTag = CONTAINING_RECORD (cur, PACKET_TAG, PT_QueueLink);
  49. // Check if this packet has to be sent on other
  50. // interfaces
  51. if (!(pktTag->PT_Flags&PT_NB_DESTROY)) {
  52. PINTERFACE_CB dstIf = pktTag->PT_InterfaceReference;
  53. PUCHAR dataPtr = pktTag->PT_Data;
  54. UINT rtCount = *(dataPtr+IPXH_XPORTCTL);
  55. PUCHAR netListPtr;
  56. UINT i;
  57. if (dstIf==NULL) {
  58. // This is a brand new packet: not sent on any
  59. // interface yet
  60. USHORT dstSock = GETUSHORT (dataPtr+IPXH_DESTSOCK);
  61. // Check if we have a static route for this name
  62. // (offset to name depends on packet dest socket)
  63. if (dstSock==IPX_NETBIOS_SOCKET)
  64. dstIf = FindNBDestination (dataPtr+NB_NAME);
  65. else if (dstSock==IPX_SMB_NAME_SOCKET)
  66. dstIf = FindNBDestination (dataPtr+SMB_NAME);
  67. else
  68. dstIf = NULL;
  69. if (dstIf!=NULL) {
  70. // Static route found, make sure this packet
  71. // won't be sent on any other interface
  72. pktTag->PT_Flags |= PT_NB_DESTROY;
  73. InterlockedIncrement (&NetbiosPacketsQuota);
  74. // Make sure the packet has not traversed
  75. // this network already
  76. for (i=0, netListPtr=dataPtr+IPXH_HDRSIZE; i<rtCount; i++,netListPtr+=4) {
  77. if (GETULONG (netListPtr)==dstIf->ICB_Network)
  78. break;
  79. }
  80. // Make sure we are allowed to send on this
  81. // interface
  82. if ((dstIf!=InternalInterface)
  83. && (i==rtCount) // Has not already traversed
  84. // this network
  85. && IS_IF_ENABLED (dstIf)
  86. && ((dstIf->ICB_NetbiosDeliver==FWD_NB_DELIVER_ALL)
  87. || (dstIf->ICB_NetbiosDeliver
  88. ==FWD_NB_DELIVER_STATIC)
  89. || ((dstIf->ICB_NetbiosDeliver
  90. ==FWD_NB_DELIVER_IF_UP)
  91. && (dstIf->ICB_Stats.OperationalState
  92. ==FWD_OPER_STATE_UP)))) {
  93. NOTHING;
  94. }
  95. else {
  96. // We have static route, but can't send it,
  97. // no point to propagate in on other interfaces
  98. // as well
  99. ReleaseInterfaceReference (dstIf);
  100. dstIf = NULL;
  101. goto FreePacket;
  102. }
  103. }
  104. else { // no static route
  105. goto FindNextInterface;
  106. }
  107. }
  108. else { // not a brand new packet (already sent on some
  109. // interfaces)
  110. FindNextInterface:
  111. // Loop through the interface list till we find
  112. // the one on which we can send
  113. while ((dstIf=GetNextInterfaceReference (dstIf))!=NULL) {
  114. // Check if we allowed to send on this interface
  115. if (IS_IF_ENABLED (dstIf)
  116. && ((dstIf->ICB_NetbiosDeliver==FWD_NB_DELIVER_ALL)
  117. || ((dstIf->ICB_NetbiosDeliver
  118. ==FWD_NB_DELIVER_IF_UP)
  119. && (dstIf->ICB_Stats.OperationalState
  120. ==FWD_OPER_STATE_UP)))) {
  121. // Make sure the packet has not traversed
  122. // this network already
  123. for (i=0, netListPtr=dataPtr+IPXH_HDRSIZE; i<rtCount; i++,netListPtr+=4) {
  124. if (GETULONG (netListPtr)==dstIf->ICB_Network)
  125. break;
  126. }
  127. // Network was not in the list
  128. if (i==rtCount)
  129. break;
  130. }
  131. }
  132. }
  133. // Save the destination interface in the packet
  134. pktTag->PT_InterfaceReference = dstIf;
  135. // Go ahead and send if we have a valid destination
  136. if (dstIf!=NULL) {
  137. SendPacket (dstIf, pktTag);
  138. // The rest does not apply: if the packet was sent or
  139. // failed, it will be queued back to NetbiosQueue;
  140. // if it was queued to interface to be connected,
  141. // a copy of it will be queued to NetbiosQueue
  142. continue;
  143. }
  144. // else no more destinations to send this packet on
  145. }
  146. else { // Packet has to be destroyed
  147. if (pktTag->PT_InterfaceReference!=NULL)
  148. ReleaseInterfaceReference (pktTag->PT_InterfaceReference);
  149. }
  150. FreePacket:
  151. IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
  152. ("IpxFwd: No more interfaces for nb packet %08lx.\n",
  153. pktTag));
  154. if (MeasuringPerformance
  155. && (pktTag->PT_PerfCounter!=0)) {
  156. LARGE_INTEGER PerfCounter = KeQueryPerformanceCounter (NULL);
  157. PerfCounter.QuadPart -= pktTag->PT_PerfCounter;
  158. KeAcquireSpinLock (&PerfCounterLock, &oldIRQL);
  159. PerfBlock.TotalNbPacketProcessingTime += PerfCounter.QuadPart;
  160. PerfBlock.NbPacketCounter += 1;
  161. if (PerfBlock.MaxNbPacketProcessingTime < PerfCounter.QuadPart)
  162. PerfBlock.MaxNbPacketProcessingTime = PerfCounter.QuadPart;
  163. KeReleaseSpinLock (&PerfCounterLock, oldIRQL);
  164. }
  165. if (!(pktTag->PT_Flags&PT_NB_DESTROY))
  166. InterlockedIncrement (&NetbiosPacketsQuota);
  167. FreePacket (pktTag);
  168. } while (!IsListEmpty (&tempQueue));
  169. KeAcquireSpinLock (&NetbiosQueueLock, &oldIRQL);
  170. if (IsListEmpty (&NetbiosQueue)
  171. || !EnterForwarder ()) {
  172. NetbiosWorkerScheduled = FALSE;
  173. }
  174. else {
  175. ExQueueWorkItem (&NetbiosWorker, DelayedWorkQueue);
  176. }
  177. }
  178. KeReleaseSpinLock (&NetbiosQueueLock, oldIRQL);
  179. LeaveForwarder ();
  180. }
  181. /*++
  182. *******************************************************************
  183. P r o c e s s N e t b i o s P a c k e t
  184. Routine Description:
  185. Processes received netbios broadcast packet (checks network list
  186. and source filter, updates input statistics)
  187. Arguments:
  188. srcIf - interfae on which packet was received
  189. pktTag - netbios packet
  190. Return Value:
  191. None
  192. *******************************************************************
  193. --*/
  194. VOID
  195. ProcessNetbiosPacket (
  196. PINTERFACE_CB srcIf,
  197. PPACKET_TAG pktTag
  198. ) {
  199. PUCHAR dataPtr, dataPtr2;
  200. UINT rtCount;
  201. UINT i, j;
  202. KIRQL oldIRQL;
  203. ULONG ulNetwork;
  204. dataPtr = pktTag->PT_Data;
  205. rtCount = *(dataPtr+IPXH_XPORTCTL);
  206. //
  207. // pmay: 264339: Make sure valid networks are listed
  208. //
  209. // We used to only verify that the source network was not
  210. // contained in the list. Now, we verify that 0 and 0xfffffff
  211. // are also absent.
  212. //
  213. for (i = 0, dataPtr += IPXH_HDRSIZE; i < rtCount; i++, dataPtr += 4)
  214. {
  215. ulNetwork = GETULONG (dataPtr);
  216. if ((srcIf->ICB_Network == ulNetwork) ||
  217. (ulNetwork == 0xffffffff) ||
  218. (ulNetwork == 0x0))
  219. {
  220. break;
  221. }
  222. }
  223. //
  224. // pmay: 272193
  225. //
  226. // nwlnknb on nt4 puts status bits into the first router slot in
  227. // the type 20 payload. As a consequence, the router has to
  228. // ignore the first slot when validating the router table so that nt4
  229. // client bcasts aren't dropped at the router.
  230. //
  231. if (rtCount == 0)
  232. {
  233. j = 1;
  234. dataPtr2 = dataPtr + 4;
  235. }
  236. else
  237. {
  238. j = i;
  239. dataPtr2 = dataPtr;
  240. }
  241. //
  242. // pmay: 264331
  243. //
  244. // Make sure the rest of the networks listed are zero
  245. //
  246. for (; j < 8; j++, dataPtr2 += 4)
  247. {
  248. ulNetwork = GETULONG (dataPtr2);
  249. if (ulNetwork != 0x0)
  250. {
  251. break;
  252. }
  253. }
  254. // We scaned the whole list and we haven't found it
  255. if ((i == rtCount) && (j == 8)) {
  256. FILTER_ACTION action;
  257. action = FltFilter (pktTag->PT_Data,
  258. GETUSHORT (pktTag->PT_Data+IPXH_LENGTH),
  259. srcIf->ICB_FilterInContext, NULL);
  260. // Apply the input filter
  261. if (action==FILTER_PERMIT) {
  262. InterlockedIncrement (&srcIf->ICB_Stats.NetbiosReceived);
  263. InterlockedIncrement (&srcIf->ICB_Stats.InDelivers);
  264. PUTULONG (srcIf->ICB_Network, dataPtr);
  265. *(pktTag->PT_Data+IPXH_XPORTCTL) += 1;
  266. IPX_NODE_CPY (pktTag->PT_Target.MacAddress, BROADCAST_NODE);
  267. // Initialize the packet
  268. pktTag->PT_InterfaceReference = NULL; // not yet sent on any
  269. // interfaces
  270. pktTag->PT_Flags = 0; // No flags
  271. QueueNetbiosPacket (pktTag);
  272. IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
  273. ("IpxFwd: Queued nb packet %08lx from if %ld.\n",
  274. pktTag, srcIf->ICB_Index));
  275. }
  276. else {
  277. ASSERT (action==FILTER_DENY_IN);
  278. IpxFwdDbgPrint (DBG_NETBIOS, DBG_WARNING,
  279. ("IpxFwd: Filtered out nb packet %08lx"
  280. " from if %ld.\n", pktTag, srcIf->ICB_Index));
  281. InterlockedIncrement (&NetbiosPacketsQuota);
  282. InterlockedIncrement (&srcIf->ICB_Stats.InFiltered);
  283. FreePacket (pktTag);
  284. }
  285. }
  286. else {
  287. IpxFwdDbgPrint (DBG_NETBIOS, DBG_WARNING,
  288. ("IpxFwd: Source net is already in nb packet %08lx"
  289. " from if %ld.\n", pktTag, srcIf->ICB_Index));
  290. InterlockedIncrement (&NetbiosPacketsQuota);
  291. InterlockedIncrement (&srcIf->ICB_Stats.InDiscards);
  292. FreePacket (pktTag);
  293. }
  294. ReleaseInterfaceReference (srcIf);
  295. }
  296. /*++
  297. *******************************************************************
  298. D e l e t e N e t b i o s Q u e u e
  299. Routine Description:
  300. Deletes the netbios bradcast queue
  301. Arguments:
  302. None
  303. Return Value:
  304. None
  305. *******************************************************************
  306. --*/
  307. VOID
  308. DeleteNetbiosQueue (
  309. void
  310. ) {
  311. while (!IsListEmpty (&NetbiosQueue)) {
  312. PPACKET_TAG pktTag = CONTAINING_RECORD (NetbiosQueue.Flink,
  313. PACKET_TAG,
  314. PT_QueueLink);
  315. RemoveEntryList (&pktTag->PT_QueueLink);
  316. if (pktTag->PT_InterfaceReference!=NULL) {
  317. ReleaseInterfaceReference (pktTag->PT_InterfaceReference);
  318. }
  319. FreePacket (pktTag);
  320. }
  321. }