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.

569 lines
11 KiB

  1. /*++
  2. Copyright (c) 2001-2002 Microsoft Corporation
  3. Module Name:
  4. peer.c
  5. Abstract:
  6. This module contains teredo peer management functions.
  7. Author:
  8. Mohit Talwar (mohitt) Wed Oct 24 14:05:08 2001
  9. Environment:
  10. Kernel mode only.
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. __inline
  15. USHORT
  16. TeredoHash(
  17. IN CONST IN6_ADDR *Address
  18. )
  19. /*++
  20. Routine Description:
  21. Hash a peer's teredo IPv6 address. Used by our static hash table
  22. implementation. Sum of mapped address and port words, mod # buckets.
  23. Arguments:
  24. Address - Supplies the peer's teredo IPv6 address.
  25. Return Value:
  26. Hashed Value.
  27. --*/
  28. {
  29. return ((Address->s6_words[1] + // Teredo mapped IPv4 address.
  30. Address->s6_words[2] + // Teredo mapped IPv4 address.
  31. Address->s6_words[3]) // Teredo mapped UDP port.
  32. % BUCKET_COUNT);
  33. }
  34. PTEREDO_PEER
  35. TeredoCreatePeer(
  36. IN PLIST_ENTRY BucketHead
  37. )
  38. /*++
  39. Routine Description:
  40. Creates a teredo peer entry.
  41. Arguments:
  42. BucketHead - Supplies the bucket list head to which the peer belongs.
  43. Return Value:
  44. NO_ERROR or failure code.
  45. Caller LOCK: Client::PeerSet.
  46. --*/
  47. {
  48. PTEREDO_PEER Peer;
  49. //
  50. // Allocate the peer structure from the appropriate heap.
  51. //
  52. Peer = (PTEREDO_PEER) HeapAlloc(
  53. TeredoClient.PeerHeap, 0, sizeof(TEREDO_PEER));
  54. if (Peer == NULL) {
  55. return NULL;
  56. }
  57. //
  58. // Initialize fields that remain unchanged for used neighors.
  59. //
  60. #if DBG
  61. Peer->Signature = TEREDO_PEER_SIGNATURE;
  62. #endif // DBG
  63. //
  64. // Insert the peer at the beginning of the LRU list.
  65. //
  66. TeredoClient.PeerSet.Size++;
  67. InsertHeadList(BucketHead, &(Peer->Link));
  68. Peer->ReferenceCount = 1;
  69. Peer->BubblePosted = FALSE;
  70. TeredoInitializePacket(&(Peer->Packet));
  71. Peer->Packet.Type = TEREDO_PACKET_BUBBLE;
  72. Peer->Packet.Buffer.len = sizeof(IP6_HDR);
  73. ASSERT(Peer->Packet.Buffer.buf == (PUCHAR) &(Peer->Bubble));
  74. //
  75. // Create the teredo bubble packet.
  76. //
  77. Peer->Bubble.ip6_flow = 0;
  78. Peer->Bubble.ip6_plen = 0;
  79. Peer->Bubble.ip6_nxt = IPPROTO_NONE;
  80. Peer->Bubble.ip6_hlim = IPV6_HOPLIMIT;
  81. Peer->Bubble.ip6_vfc = IPV6_VERSION;
  82. //
  83. // Obtain a reference on the teredo client for the peer.
  84. //
  85. TeredoReferenceClient();
  86. return Peer;
  87. }
  88. VOID
  89. TeredoDestroyPeer(
  90. IN PTEREDO_PEER Peer
  91. )
  92. /*++
  93. Routine Description:
  94. Destroys a peer entry.
  95. Arguments:
  96. Peer - Supplies the peer entry to destroy.
  97. Return Value:
  98. NO_ERROR.
  99. --*/
  100. {
  101. ASSERT(IsListEmpty(&(Peer->Link)));
  102. ASSERT(Peer->ReferenceCount == 0);
  103. ASSERT(Peer->BubblePosted == FALSE);
  104. HeapFree(TeredoClient.PeerHeap, 0, (PUCHAR) Peer);
  105. //
  106. // Release the peer's reference on the teredo client.
  107. // This might cause the client to be cleaned up, hence we do it last.
  108. //
  109. TeredoDereferenceClient();
  110. }
  111. VOID
  112. TeredoInitializePeer(
  113. OUT PTEREDO_PEER Peer,
  114. IN CONST IN6_ADDR *Address
  115. )
  116. /*++
  117. Routine Description:
  118. Initialize the state of a peer upon creation or reuse.
  119. The peer is already inserted in the appropriate bucket.
  120. Arguments:
  121. Peer - Returns a peer with its state initialized.
  122. Address - Supplies the peer's teredo IPv6 address.
  123. Return Value:
  124. None.
  125. Caller LOCK: Client::PeerSet.
  126. --*/
  127. {
  128. ASSERT(Peer->ReferenceCount == 1);
  129. ASSERT(Peer->BubblePosted == FALSE);
  130. //
  131. // Reset fields for both new and used peers...
  132. //
  133. Peer->LastReceive = Peer->LastTransmit =
  134. TeredoClient.Time - TEREDO_REFRESH_INTERVAL;
  135. Peer->Address = *Address;
  136. Peer->BubbleCount = 0;
  137. //
  138. // Teredo mapped UDP port & IPv4 address.
  139. //
  140. TeredoParseAddress(
  141. Address,
  142. &(Peer->Packet.SocketAddress.sin_addr),
  143. &(Peer->Packet.SocketAddress.sin_port));
  144. //
  145. // Update fields in the teredo bubble packet.
  146. //
  147. Peer->Bubble.ip6_dest = Peer->Address;
  148. // Peer->Bubble.ip6_src... Filled in when sending.
  149. }
  150. VOID
  151. TeredoDeletePeer(
  152. IN OUT PTEREDO_PEER Peer
  153. )
  154. /*++
  155. Routine Description:
  156. Delete a peer from the peer set, thus initiating its destruction.
  157. Arguments:
  158. Interface - Returns a peer deleted from the peer set.
  159. Return Value:
  160. None.
  161. Caller LOCK: Client::PeerSet.
  162. --*/
  163. {
  164. //
  165. // Unlink the neighbor from the peer set...
  166. //
  167. TeredoClient.PeerSet.Size--;
  168. RemoveEntryList(&(Peer->Link));
  169. InitializeListHead(&(Peer->Link));
  170. //
  171. // And release the reference obtained for being in it.
  172. //
  173. TeredoDereferencePeer(Peer);
  174. }
  175. BOOL
  176. __inline
  177. TeredoCachedPeer(
  178. IN PTEREDO_PEER Peer
  179. )
  180. /*++
  181. Routine Description:
  182. Determine if the peer belonging to the PeerSet is cached.
  183. Arguments:
  184. Peer - Supplies the peer being inspected.
  185. The peer should still be a member of the peer set.
  186. Return Value:
  187. TRUE if cached, FALSE otherwise.
  188. --*/
  189. {
  190. //
  191. // The peer does belong to a peer set. Right?
  192. //
  193. ASSERT(!IsListEmpty(&(Peer->Link)));
  194. return (Peer->ReferenceCount == 1);
  195. }
  196. PTEREDO_PEER
  197. TeredoReusePeer(
  198. IN PLIST_ENTRY BucketHead
  199. )
  200. /*++
  201. Routine Description:
  202. Reuse an existing peer entry from the bucket if one is cached.
  203. Arguments:
  204. BucketHead - Supplies the bucket list head to which the peer belongs.
  205. Return Value:
  206. Peer entry to reuse or NULL.
  207. Caller LOCK: Client::PeerSet.
  208. --*/
  209. {
  210. PLIST_ENTRY Next;
  211. PTEREDO_PEER Peer;
  212. Next = BucketHead->Blink;
  213. if (Next == BucketHead) {
  214. return NULL;
  215. }
  216. Peer = Cast(CONTAINING_RECORD(Next, TEREDO_PEER, Link), TEREDO_PEER);
  217. if (TeredoCachedPeer(Peer)) {
  218. //
  219. // Insert the peer at the beginning of the LRU list.
  220. //
  221. RemoveEntryList(Next);
  222. InsertHeadList(BucketHead, Next);
  223. return Peer;
  224. }
  225. return NULL;
  226. }
  227. PTEREDO_PEER
  228. TeredoReuseOrCreatePeer(
  229. IN PLIST_ENTRY BucketHead,
  230. IN CONST IN6_ADDR *Address
  231. )
  232. /*++
  233. Routine Description:
  234. Reuse or create a teredo peer and (re)initialize its state.
  235. Arguments:
  236. BucketHead - Supplies the bucket list head to which the peer belongs.
  237. Address - Supplies the peer's teredo IPv6 address.
  238. Return Value:
  239. Peer entry to use or NULL.
  240. Caller LOCK: Client::PeerSet.
  241. --*/
  242. {
  243. PTEREDO_PEER Peer;
  244. Peer = TeredoReusePeer(BucketHead);
  245. if (Peer == NULL) {
  246. Peer = TeredoCreatePeer(BucketHead);
  247. }
  248. if (Peer == NULL) {
  249. return NULL;
  250. }
  251. TeredoInitializePeer(Peer, Address);
  252. return Peer;
  253. }
  254. PTEREDO_PEER
  255. TeredoFindPeer(
  256. IN PLIST_ENTRY BucketHead,
  257. IN CONST IN6_ADDR *Address
  258. )
  259. /*++
  260. Routine Description:
  261. Find a peer entry with the given address.
  262. Arguments:
  263. BucketHead - Supplies the bucket list head to which the peer belongs.
  264. Address - Supplies the peer's teredo IPv6 address.
  265. Return Value:
  266. Peer entry or NULL.
  267. Caller LOCK: Client::PeerSet.
  268. --*/
  269. {
  270. PLIST_ENTRY Next;
  271. PTEREDO_PEER Peer;
  272. for (Next = BucketHead->Flink; Next != BucketHead; Next = Next->Flink) {
  273. Peer = Cast(
  274. CONTAINING_RECORD(Next, TEREDO_PEER, Link), TEREDO_PEER);
  275. if (TeredoEqualPrefix(&(Peer->Address), Address)) {
  276. return Peer; // found!
  277. }
  278. }
  279. return NULL; // not found!
  280. }
  281. PTEREDO_PEER
  282. TeredoFindOrCreatePeer(
  283. IN CONST IN6_ADDR *Address
  284. )
  285. /*++
  286. Routine Description:
  287. Find a peer entry with the given teredo IPv6 address.
  288. Create one if the search is unsuccessful.
  289. Returns a reference on the found/created peer to the caller.
  290. Arguments:
  291. Address - Supplies the peer's teredo IPv6 address.
  292. Return Value:
  293. Peer entry or NULL.
  294. --*/
  295. {
  296. PTEREDO_PEER Peer = NULL;
  297. PLIST_ENTRY Head = TeredoClient.PeerSet.Bucket + TeredoHash(Address);
  298. ASSERT(Address->s6_words[0] == TeredoIpv6ServicePrefix.s6_words[0]);
  299. //
  300. // Note: Since we typically do only a small amount of work while holding
  301. // this lock we don't need it to be a multiple-reader-single-writer lock!
  302. //
  303. EnterCriticalSection(&(TeredoClient.PeerSet.Lock));
  304. if (TeredoClient.State != TEREDO_STATE_OFFLINE) {
  305. Peer = TeredoFindPeer(Head, Address);
  306. if (Peer == NULL) {
  307. Peer = TeredoReuseOrCreatePeer(Head, Address);
  308. }
  309. if (Peer != NULL) {
  310. TeredoReferencePeer(Peer);
  311. }
  312. }
  313. LeaveCriticalSection(&(TeredoClient.PeerSet.Lock));
  314. return Peer;
  315. }
  316. DWORD
  317. TeredoInitializePeerSet(
  318. VOID
  319. )
  320. /*++
  321. Routine Description:
  322. Initializes the peer set, organized as a statically sized hash table.
  323. Arguments:
  324. None.
  325. Return Value:
  326. NO_ERROR or failure code.
  327. --*/
  328. {
  329. ULONG i;
  330. __try {
  331. InitializeCriticalSection(&(TeredoClient.PeerSet.Lock));
  332. }
  333. __except(EXCEPTION_EXECUTE_HANDLER) {
  334. return GetLastError();
  335. }
  336. TeredoClient.PeerSet.Size = 0;
  337. for (i = 0; i < BUCKET_COUNT; i++) {
  338. InitializeListHead(TeredoClient.PeerSet.Bucket + i);
  339. }
  340. return NO_ERROR;
  341. }
  342. VOID
  343. TeredoUninitializePeerSet(
  344. VOID
  345. )
  346. /*++
  347. Routine Description:
  348. Uninitializes the peer set. Typically invoked when going offline.
  349. Deletes all existing peers.
  350. Arguments:
  351. None.
  352. Return Value:
  353. None.
  354. --*/
  355. {
  356. PLIST_ENTRY Head, Next;
  357. PTEREDO_PEER Peer;
  358. ULONG i;
  359. ASSERT(TeredoClient.State == TEREDO_STATE_OFFLINE);
  360. EnterCriticalSection(&(TeredoClient.PeerSet.Lock));
  361. for (i = 0;
  362. (i < BUCKET_COUNT) && (TeredoClient.PeerSet.Size != 0);
  363. i++) {
  364. Head = TeredoClient.PeerSet.Bucket + i;
  365. while (!IsListEmpty(Head)) {
  366. Next = RemoveHeadList(Head);
  367. Peer = Cast(
  368. CONTAINING_RECORD(Next, TEREDO_PEER, Link), TEREDO_PEER);
  369. TeredoDeletePeer(Peer);
  370. }
  371. }
  372. ASSERT(TeredoClient.PeerSet.Size == 0); // no more, no less
  373. LeaveCriticalSection(&(TeredoClient.PeerSet.Lock));
  374. }
  375. VOID
  376. TeredoCleanupPeerSet(
  377. VOID
  378. )
  379. /*++
  380. Routine Description:
  381. Cleans up the peer set. Typically invoked upon service stop.
  382. All peers should have been deleted.
  383. Arguments:
  384. None.
  385. Return Value:
  386. None.
  387. --*/
  388. {
  389. ASSERT(TeredoClient.PeerSet.Size == 0); // no more, no less
  390. DeleteCriticalSection(&(TeredoClient.PeerSet.Lock));
  391. }