Source code of Windows XP (NT5)
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.

7581 lines
274 KiB

  1. /*++
  2. Copyright(c) 1998,99 Microsoft Corporation
  3. Module Name:
  4. main.c
  5. Abstract:
  6. Windows Load Balancing Service (WLBS)
  7. Driver - packet handling
  8. Author:
  9. kyrilf
  10. --*/
  11. #include <ndis.h>
  12. #include "main.h"
  13. #include "prot.h"
  14. #include "nic.h"
  15. #include "univ.h"
  16. #include "wlbsip.h"
  17. #include "util.h"
  18. #include "load.h"
  19. #include "wlbsparm.h"
  20. #include "params.h"
  21. #include "log.h"
  22. #include "trace.h"
  23. EXPORT
  24. VOID
  25. NdisIMCopySendPerPacketInfo(
  26. IN PNDIS_PACKET DstPacket,
  27. IN PNDIS_PACKET SrcPacket
  28. );
  29. EXPORT
  30. VOID
  31. NdisIMCopySendCompletePerPacketInfo(
  32. IN PNDIS_PACKET DstPacket,
  33. PNDIS_PACKET SrcPacket
  34. );
  35. //
  36. // Internal functions
  37. //
  38. BOOLEAN Main_ApplyChangeWithoutReStart(PMAIN_CTXT ctxtp,
  39. CVY_PARAMS* pOldParams,
  40. const CVY_PARAMS* pCurParam);
  41. #if defined (SBH)
  42. NDIS_STATUS Main_QueryPerf (
  43. PMAIN_CTXT ctxtp,
  44. PCVY_DRIVER_PERF pPerf);
  45. #endif
  46. /* GLOBALS */
  47. MAIN_ADAPTER univ_adapters [CVY_MAX_ADAPTERS]; // ###### ramkrish
  48. ULONG univ_adapters_count = 0;
  49. /* need this to bootstrap Main_ioctl since it will run without any context */
  50. static PVOID ioctrl_ctxtp;
  51. static ULONG log_module_id = LOG_MODULE_MAIN;
  52. /* The head of the BDA team list. */
  53. PBDA_TEAM univ_bda_teaming_list = NULL;
  54. /* PROCEDURES */
  55. /*
  56. * Function: Main_alloc_team
  57. * Description: This function allocates and initializes a BDA_TEAM structure.
  58. * Parameters: ctxtp - a pointer to the MAIN_CTXT structure for this adapter
  59. * Returns: PBDA_TEAM - a pointer to a new BDA_TEAM structure if successful, NULL if not.
  60. * Author: shouse, 3.29.01
  61. * Notes:
  62. */
  63. PBDA_TEAM Main_alloc_team (IN PMAIN_CTXT ctxtp, IN PWSTR team_id) {
  64. PUCHAR ptr;
  65. PBDA_TEAM team;
  66. NDIS_STATUS status;
  67. UNIV_PRINT(("Main_alloc_team: Entering..."));
  68. /* Allocate a BDA_TEAM structure. */
  69. status = NdisAllocateMemoryWithTag(&ptr, sizeof(BDA_TEAM), UNIV_POOL_TAG);
  70. if (status != NDIS_STATUS_SUCCESS) {
  71. UNIV_PRINT(("Main_alloc_team: Unable to allocate a team. Exiting..."));
  72. LOG_MSG2(MSG_ERROR_MEMORY, MSG_NONE, sizeof(BDA_TEAM), status);
  73. return NULL;
  74. }
  75. /* Make sure that ptr actually points to something. */
  76. ASSERT(ptr);
  77. /* Zero the memory out. */
  78. NdisZeroMemory(ptr, sizeof(BDA_TEAM));
  79. /* Cast the new memory to a team pointer. */
  80. team = (PBDA_TEAM)ptr;
  81. /* Set the default field values. This is redundant (since
  82. we just called NdisZeroMemory), but whatever. */
  83. team->prev = NULL;
  84. team->next = NULL;
  85. team->load = NULL;
  86. team->load_lock = NULL;
  87. team->active = FALSE;
  88. team->membership_count = 0;
  89. team->membership_fingerprint = 0;
  90. team->membership_map = 0;
  91. team->consistency_map = 0;
  92. /* Copy the team ID into the team structure. */
  93. NdisMoveMemory(team->team_id, team_id, CVY_MAX_BDA_TEAM_ID * sizeof(WCHAR));
  94. UNIV_PRINT(("Main_alloc_team: Exiting..."));
  95. return team;
  96. }
  97. /*
  98. * Function: Main_free_team
  99. * Description: This function frees the memory used by a BDA_TEAM.
  100. * Parameters: team - a pointer to the team to be freed.
  101. * Returns: Nothing.
  102. * Author: shouse, 3.29.01
  103. * Notes:
  104. */
  105. VOID Main_free_team (IN PBDA_TEAM team) {
  106. UNIV_PRINT(("Main_free_team: Entering..."));
  107. /* Make sure that team actually points to something. */
  108. ASSERT(team);
  109. /* Free the memory that the team structure is using. */
  110. NdisFreeMemory((PUCHAR)team, sizeof(BDA_TEAM), 0);
  111. UNIV_PRINT(("Main_free_team: Exiting..."));
  112. }
  113. /*
  114. * Function: Main_find_team
  115. * Description: This function searches the linked list of teams looking for
  116. * a given team ID. If team with the same ID is found, a pointer
  117. * to that team is returned, otherwise NULL is returned to indicate
  118. * that no such team exists.
  119. * Parameters: ctxtp - a pointer to the MAIN_CTXT structure for this team.
  120. * team_id - a unicode string containing the team ID, which must be a GUID.
  121. * Returns: PBDA_TEAM - a pointer to the team if found, NULL otherwise.
  122. * Author: shouse, 3.29.01
  123. * Notes: This function should be called with the global teaming lock already acquired!!!
  124. */
  125. PBDA_TEAM Main_find_team (IN PMAIN_CTXT ctxtp, IN PWSTR team_id) {
  126. NDIS_STRING existing_team;
  127. NDIS_STRING new_team;
  128. PBDA_TEAM team;
  129. UNIV_PRINT(("Main_find_team: Entering..."));
  130. /* Loop through all teams in the linked list. If we find a matching
  131. team ID, return a pointer to the team; otherwise, return NULL. */
  132. for (team = univ_bda_teaming_list; team; team = team->next) {
  133. /* If we have a match, return a pointer to the team. */
  134. if (NdisEqualMemory((PVOID)team->team_id, (PVOID)team_id, sizeof(WCHAR) * CVY_MAX_BDA_TEAM_ID)) {
  135. UNIV_PRINT(("Main_find_team: Team found. Exiting..."));
  136. return team;
  137. }
  138. }
  139. UNIV_PRINT(("Main_find_team: Team not found. Exiting..."));
  140. return NULL;
  141. }
  142. /*
  143. * Function: Main_teaming_get_member_id
  144. * Description: This function assigns a team member a unique, zero-indexed integer ID,
  145. * which is used by the member as in index in a consistency bit map. Each
  146. * member sets their bit in the consistecy bit map, based on heartbeat
  147. * observations, that is used by the master of the team to determine whether
  148. * or not the team should be in an active state.
  149. * Parameters: team - a pointer to the team which the adapter is joining.
  150. * id - out parameter to hold the new ID.
  151. * Returns: BOOLEAN - always TRUE now, but there may be a need to return failure in the future.
  152. * Author: shouse, 3.29.01
  153. * Notes: This function should be called with the team lock already acquired!!!
  154. */
  155. BOOLEAN Main_teaming_get_member_id (IN PBDA_TEAM team, OUT PULONG id) {
  156. ULONG index;
  157. ULONG map;
  158. UNIV_PRINT(("Main_teaming_get_member_id: Entering..."));
  159. /* Make sure that team actually points to something. */
  160. ASSERT(team);
  161. /* Make sure that ID actually points to something. */
  162. ASSERT(id);
  163. /* Loop through the membership map looking for the first reset bit. Because members
  164. can come and go, this bit will not always be in the (num_membes)th position. For
  165. example, it is perfectly plausible for the membership_map to look like (binary)
  166. 0000 0000 0000 0000 0000 0100 1110 0111, in which case the ID returned by this
  167. function would be three. */
  168. for (index = 0, map = team->membership_map;
  169. index <= CVY_BDA_MAXIMUM_MEMBER_ID, map;
  170. index++, map >>= 1)
  171. if (!(map & 0x00000001)) break;
  172. /* We assert that the index must be less than the maximum number of adapters
  173. (CVY_BDA_MAXIMUM_MEMBER_ID = CVY_MAX_ADAPTERS - 1). */
  174. ASSERT(index <= CVY_BDA_MAXIMUM_MEMBER_ID);
  175. /* Set the member ID. */
  176. *id = index;
  177. /* Set our bit in the membership map. */
  178. team->membership_map |= (1 << *id);
  179. /* Set our bit in the consistency map. By default, we assume that this member
  180. is consistent and heartbeats on this adapter can deternmine otherwise. */
  181. team->consistency_map |= (1 << *id);
  182. UNIV_PRINT(("Main_teaming_get_member_id: Exiting..."));
  183. /* We may have reason to fail this call in the future, but for now, we always succeed. */
  184. return TRUE;
  185. }
  186. /*
  187. * Function: Main_teaming_put_member_id
  188. * Description: This function is called when a member leaves its team, at which
  189. * time its ID is put back into the ID pool.
  190. * Parameters: team - a pointer to the team which this adapter is leaving.
  191. * id - the ID, which this function will reset before returning.
  192. * Returns: BOOLEAN - always TRUE now, but there may be a need to return failure in the future.
  193. * Author: shouse, 3.29.01
  194. * Notes: This function should be called with the team lock already acquired!!!
  195. */
  196. BOOLEAN Main_teaming_put_member_id (IN PBDA_TEAM team, IN OUT PULONG id) {
  197. UNIV_PRINT(("Main_teaming_put_member_id: Entering..."));
  198. /* Make sure that team actually points to something. */
  199. ASSERT(team);
  200. /* Make sure that ID actually points to something. */
  201. ASSERT(id);
  202. /* Reet our bit in the membership map. This effectively prevents
  203. us from influencing the active state of the team. */
  204. team->membership_map &= ~(1 << *id);
  205. /* Reet our bit in the consistency map. */
  206. team->consistency_map &= ~(1 << *id);
  207. /* Set the member ID back to an invalid value. */
  208. *id = CVY_BDA_INVALID_MEMBER_ID;
  209. UNIV_PRINT(("Main_teaming_put_member_id: Exiting..."));
  210. /* We may have reason to fail this call in the future, but for now, we always succeed. */
  211. return TRUE;
  212. }
  213. /*
  214. * Function: Main_queue_team
  215. * Description: This fuction queues a team onto the global doubly-linked list of BDA teams
  216. * (univ_bda_teaming_list). Insertions always occur at the front of the list.
  217. * Parameters: team - a pointer to the team to queue onto the list.
  218. * Returns: Nothing.
  219. * Author: shouse, 3.29.01
  220. * Notes: This function should be called with the global teaming lock already acquired!!!
  221. */
  222. VOID Main_queue_team (IN PBDA_TEAM team) {
  223. UNIV_PRINT(("Main_queue_team: Entering..."));
  224. /* Make sure that team actually points to something. */
  225. ASSERT(team);
  226. /* Insert at the head of the list by setting next to the current
  227. head and pointing the global head pointer to the new team. */
  228. team->prev = NULL;
  229. team->next = univ_bda_teaming_list;
  230. univ_bda_teaming_list = team;
  231. /* If we are not the only team in the list, then we have to
  232. set my successor's previous pointer to point to me. */
  233. if (team->next) team->next->prev = team;
  234. UNIV_PRINT(("Main_queue_team: Exiting..."));
  235. }
  236. /*
  237. * Function: Main_dequeue_team
  238. * Description: This function removes a given team from the global doubly-linked
  239. * list of teams (univ_bda_teaming_list).
  240. * Parameters: team - a pointer to the team to remove from the list.
  241. * Returns: Nothing.
  242. * Author: shouse, 3.29.01
  243. * Notes: This function should be called with the global teaming lock already acquired!!!
  244. */
  245. VOID Main_dequeue_team (IN PBDA_TEAM team) {
  246. UNIV_PRINT(("Main_dequeue_team: Entering..."));
  247. /* Make sure that team actually points to something. */
  248. ASSERT(team);
  249. /* Special case when we are the first team in the list, in which case, we
  250. have no previous pointer and the head of the list needs to be reset. */
  251. if (!team->prev) {
  252. /* Point the global head of the list to the next team in the list,
  253. which CAN be NULL, meaning that the list is now empty. */
  254. univ_bda_teaming_list = team->next;
  255. /* If there was a team after me in the list, who is now the new
  256. head of the list, set its previous pointer to NULL. */
  257. if (team->next) team->next->prev = NULL;
  258. } else {
  259. /* Point the previous node's next pointer to my successor in the
  260. list, which CAN be NULL if I was the last team in the list. */
  261. team->prev->next = team->next;
  262. /* If there is a team after me in the list, point its previous
  263. pointer to my predecessor. */
  264. if (team->next) team->next->prev = team->prev;
  265. }
  266. UNIV_PRINT(("Main_dequeue_team: Exiting..."));
  267. }
  268. /*
  269. * Function: Main_get_team
  270. * Description: This function returns a team for the given team ID. If the team already
  271. * exists in the global teaming list, it is returned. Otherwise, a new team
  272. * is allocated, initialized and returned. Before a team is returned, however,
  273. * it is properly referenced by incrementing the reference count (membership_count),
  274. * assigning a team member ID to the requestor and fingerprinting the team with
  275. * the member's primary cluster IP address.
  276. * Parameters: ctxtp - a pointer to the MAIN_CTXT structure for this adapter.
  277. * team_id - a unicode string (GUID) uniquely identifying the team to retrieve.
  278. * Returns: PBDA_TEAM - a pointer to the requested team. NULL if it does not exists and
  279. * a new team cannot be allocated, or if the team ID is invalid (empty).
  280. * Author: shouse, 3.29.01
  281. * Notes: This function should be called with the global teaming lock already acquired!!!
  282. */
  283. PBDA_TEAM Main_get_team (IN PMAIN_CTXT ctxtp, IN PWSTR team_id) {
  284. PBDA_TEAM team;
  285. UNIV_PRINT(("Main_get_team: Entering..."));
  286. /* Make sure that team_id actually points to something. */
  287. if (!team_id || team_id[0] == L'\0') {
  288. UNIV_PRINT(("Main_get_team: Invalid parameter. Exiting..."));
  289. return NULL;
  290. }
  291. /* Try to find a previous instance of this team in the global list.
  292. If we can't find it in the list, then allocate a new team. */
  293. if (!(team = Main_find_team(ctxtp, ctxtp->params.bda_teaming.team_id))) {
  294. /* Allocate and initialize a new team. */
  295. if (!(team = Main_alloc_team(ctxtp, ctxtp->params.bda_teaming.team_id))) {
  296. UNIV_PRINT(("Main_get_team: Error attempting to allocate memory for a team. Exiting..."));
  297. return NULL;
  298. }
  299. /* If a new team was allocated, insert it into the list. */
  300. Main_queue_team(team);
  301. }
  302. /* Increment the reference count on this team. This reference count prevents
  303. a team from being destroyed while somebody is still using it. */
  304. team->membership_count++;
  305. /* Get a team member ID, which is my index into the consistency bit map. */
  306. Main_teaming_get_member_id(team, &ctxtp->bda_teaming.member_id);
  307. /* The fingerprint field is a cumulative XOR of all primary cluster IPs in the team. We
  308. only use the two least significant bytes of the cluster IP, which, because the
  309. cluster IP address is stored in host order, are the two most significant bytes. */
  310. team->membership_fingerprint ^= ((ctxtp->cl_ip_addr >> 16) & 0x0000ffff);
  311. UNIV_PRINT(("Main_get_team: Exiting..."));
  312. return team;
  313. }
  314. /*
  315. * Function: Main_put_team
  316. * Description: This function releases a reference on a team and frees the team if
  317. * no references remain. Dereferencing includes decrementing the
  318. * membership_count, releasing this member's ID and removing our
  319. * fingerprint from the team.
  320. * Parameters: ctxtp - a pointer to the MAIN_CTXT structure for this adapter.
  321. * team - a pointer to the team to dereference.
  322. * Returns: Nothing.
  323. * Author: shouse, 3.29.01
  324. * Notes: This function should be called with the global teaming lock already acquired!!!
  325. */
  326. VOID Main_put_team (IN PMAIN_CTXT ctxtp, IN PBDA_TEAM team) {
  327. UNIV_PRINT(("Main_put_team: Entering..."));
  328. /* Make sure that team actually points to something. */
  329. ASSERT(team);
  330. /* The fingerprint field is a cumulative XOR of all primary cluster IPs in the team.
  331. We only use the two least significant bytes of the cluster IP, which, because the
  332. cluster IP address is stored in host order, are the two most significant bytes.
  333. Because a fingerprint is an XOR, the act of removing our fingerprint is the same
  334. as it was to add it - we simply XOR our primary cluster IP address to remove it.
  335. ((NUM1 ^ NUM2) ^ NUM2) equals NUM1. */
  336. team->membership_fingerprint ^= ((ctxtp->cl_ip_addr >> 16) & 0x0000ffff);
  337. /* Release our team member ID back into the free pool. */
  338. Main_teaming_put_member_id(team, &ctxtp->bda_teaming.member_id);
  339. /* Decrement the number of adapters in this team and remove and free the team
  340. if this is the last reference on the team. */
  341. if (!--team->membership_count) {
  342. /* Remove the team from the list. */
  343. Main_dequeue_team(team);
  344. /* Free the memory used by the team. */
  345. Main_free_team(team);
  346. }
  347. UNIV_PRINT(("Main_put_team: Exiting..."));
  348. }
  349. /*
  350. * Function: Main_teaming_check_consistency
  351. * Description: This function is called by all adapters during Main_ping, wherein
  352. * the master of every team should check its team for consitency and
  353. * mark the team active if it is consistent. Teams are marked incon-
  354. * sistent and inactive by the load module or when the master of an
  355. * existing team is removed. Because on the master performs the con-
  356. * sistency check in this function, a team without a master can NEVER
  357. * be marked active.
  358. * Parameters: ctxtp - a pointer to the adapter's MAIN_CTXT structure.
  359. * Returns: Nothing
  360. * Author: shouse, 3.29.01
  361. * Notes: This function acquires the global teaming lock.
  362. */
  363. VOID Main_teaming_check_consistency (IN PMAIN_CTXT ctxtp) {
  364. PBDA_TEAM team;
  365. /* We check whether or not we are teaming without grabbing the global teaming
  366. lock in an effort to minimize the common case - teaming is a special mode
  367. of operation that is only really useful in a clustered firewall scenario.
  368. So, if we aren't teaming, just bail out here; if we really aren't teaming,
  369. or are in the process of leaving a team, then no worries; if however, we were
  370. teaming or in the process of joining a team, then we'll just catch this
  371. the next time through. If we do think we're teaming, then we'll go ahead
  372. and grab the global lock to make sure. */
  373. if (!ctxtp->bda_teaming.active) return;
  374. NdisAcquireSpinLock(&univ_bda_teaming_lock);
  375. /* If we actually aren't part of a team, bail out - nothing to do. */
  376. if (!ctxtp->bda_teaming.active) {
  377. NdisReleaseSpinLock(&univ_bda_teaming_lock);
  378. return;
  379. }
  380. /* If we aren't the master of our team, bail out - nothing to do.
  381. Only the master can change the state of a team to active. */
  382. if (!ctxtp->bda_teaming.master) {
  383. NdisReleaseSpinLock(&univ_bda_teaming_lock);
  384. return;
  385. }
  386. /* Extract a pointer to my team. */
  387. team = ctxtp->bda_teaming.bda_team;
  388. /* Make sure that the team exists. */
  389. ASSERT(team);
  390. /* If all members of my team are consistent, then activate the team. */
  391. if (team->membership_map == team->consistency_map) {
  392. if (!team->active) {
  393. LOG_MSG(MSG_INFO_BDA_TEAM_REACTIVATED, MSG_NONE);
  394. team->active = TRUE;
  395. }
  396. }
  397. NdisReleaseSpinLock(&univ_bda_teaming_lock);
  398. }
  399. /*
  400. * Function: Main_teaming_ip_addr_change
  401. * Description: This function is called from Main_ip_addr_init when the primary
  402. * cluster IP address of an adapter changes (potentially). We need
  403. * to recognize this to properly re-fingerprint the team.
  404. * Parameters: ctxtp - a pointer to the MAIN_CTXT structure for this adapter.
  405. * old_ip - the old cluster IP addres (as a DWORD).
  406. * new_ip - the new cluster IP address (as a DWORD).
  407. * Returns: Nothing.
  408. * Author: shouse, 3.29.01
  409. * Notes: This function acquires the global teaming lock.
  410. */
  411. VOID Main_teaming_ip_addr_change (IN PMAIN_CTXT ctxtp, IN ULONG old_ip, IN ULONG new_ip) {
  412. PBDA_TEAM team;
  413. UNIV_PRINT(("Main_teaming_ip_addr_change: Entering..."));
  414. NdisAcquireSpinLock(&univ_bda_teaming_lock);
  415. /* If we aren't part of a team, bail out - nothing to do. Because this function is only
  416. called during a re-configuration, we won't worry about optimizing and not grabbing the
  417. lock as is done in some of the hot paths. */
  418. if (!ctxtp->bda_teaming.active) {
  419. UNIV_PRINT(("Main_teaming_ip_addr_change: This adapter is not part of a team. Exiting..."));
  420. NdisReleaseSpinLock(&univ_bda_teaming_lock);
  421. return;
  422. }
  423. /* Grab a pointer to the team. */
  424. team = ctxtp->bda_teaming.bda_team;
  425. /* Make sure that team actually points to something. */
  426. ASSERT(team);
  427. /* Remove the old cluster IP address by undoing the XOR. We only use the two
  428. least significant bytes of the cluster IP, which, because the cluster IP
  429. address is stored in host order, are the two most significant bytes. */
  430. team->membership_fingerprint ^= ((old_ip >> 16) & 0x0000ffff);
  431. /* XOR with the new cluster IP address. We only use the two least
  432. significant bytes of the cluster IP, which, because the cluster IP
  433. address is stored in host order, are the two most significant bytes. */
  434. team->membership_fingerprint ^= ((new_ip >> 16) & 0x0000ffff);
  435. NdisReleaseSpinLock(&univ_bda_teaming_lock);
  436. UNIV_PRINT(("Main_teaming_ip_addr_change: Exiting..."));
  437. }
  438. /*
  439. * Function: Main_teaming_cleanup
  440. * Description: This function is called from Main_cleanup (or Main_teaming_init) to
  441. * cleanup any teaming configuration that may exist on an adapter. To
  442. * do so, we cleanup our membership state and dereference the team. If
  443. * we are the master for the team, however, we have to wait until there
  444. * are no more references on our load module before allowing the operation
  445. * to complete, because this might be called in the unbind path, in
  446. * which case, our load module would be going away.
  447. * Parameters: ctxtp - a pointer to the MAIN_CTXT structure for this adapter.
  448. * Returns: Nothing.
  449. * Author: shouse, 3.29.01
  450. * Notes: This function acquires the global teaming lock.
  451. */
  452. VOID Main_teaming_cleanup (IN PMAIN_CTXT ctxtp) {
  453. PBDA_TEAM team;
  454. UNIV_PRINT(("Main_teaming_cleanup: Entering..."));
  455. NdisAcquireSpinLock(&univ_bda_teaming_lock);
  456. /* If we aren't part of a team, bail out - nothing to do. */
  457. if (!ctxtp->bda_teaming.active) {
  458. UNIV_PRINT(("Main_teaming_cleanup: This adapter is not part of a team. Exiting..."));
  459. NdisReleaseSpinLock(&univ_bda_teaming_lock);
  460. return;
  461. }
  462. /* Inactivate teaming on this adapter. This will cause other entities like the
  463. load module and send/receive paths to stop thinking in teaming mode. */
  464. ctxtp->bda_teaming.active = FALSE;
  465. /* Grab a pointer to the team. */
  466. team = ctxtp->bda_teaming.bda_team;
  467. /* Make sure that team actually points to something. */
  468. ASSERT(team);
  469. /* If we are the master for this team, make sure that all references to our load
  470. module have been released and then remove our load information from the team. */
  471. if (ctxtp->bda_teaming.master) {
  472. /* Mark the team as inactive - a team cannot function without a master. Members
  473. of an inactive team will NOT accept packets and therefore will not reference
  474. our load module further while we wait for the reference count to go to zero. */
  475. team->active = FALSE;
  476. NdisReleaseSpinLock(&univ_bda_teaming_lock);
  477. /* No need to worry - the team pointer cannot go away even though we don't have
  478. the lock acquired; we have a reference on the team until we call Main_put_team. */
  479. while (Load_get_reference_count(team->load)) {
  480. UNIV_PRINT(("Main_teaming_cleanup: Sleeping...\n"));
  481. /* Sleep while there are references on our load module. */
  482. Nic_sleep(10);
  483. }
  484. NdisAcquireSpinLock(&univ_bda_teaming_lock);
  485. /* Remove the pointer to my load module. We wait until now to prevent another
  486. adapter from joining the team claiming to be the master until we are done
  487. waiting for references on our load module to go away. */
  488. team->load = NULL;
  489. team->load_lock = NULL;
  490. /* If we have just left a team without a master, log an event to notify
  491. the user that a team cannot function without a designated master. */
  492. LOG_MSG(MSG_INFO_BDA_MASTER_LEAVE, MSG_NONE);
  493. }
  494. /* Reset the teaming context (member_id is set and reset by Main_get(put)_team). */
  495. ctxtp->bda_teaming.reverse_hash = 0;
  496. ctxtp->bda_teaming.master = 0;
  497. /* Remove the pointer to the team structure. */
  498. ctxtp->bda_teaming.bda_team = NULL;
  499. /* Decrements the reference count and frees the team if necessary. */
  500. Main_put_team(ctxtp, team);
  501. NdisReleaseSpinLock(&univ_bda_teaming_lock);
  502. UNIV_PRINT(("Main_teaming_cleanup: Exiting..."));
  503. return;
  504. }
  505. /*
  506. * Function: Main_teaming_init
  507. * Description: This function is called by either Main_init or Main_ctrl to re-initialize
  508. * the teaming confguration on this adapter. If the new teaming configuration,
  509. * which is stored in ctxtp->params is the same as the current configuration,
  510. * then we don't need to bother. Otherwise, if we are already part of a team,
  511. * we begin by cleaning up that state, which may unnecssary in some cases, but
  512. * it makes things simpler and more straight-forward, so we'll live with it.
  513. * Parameters: ctxtp - a pointer to the MAIN_CTXT structure for this adapter.
  514. * Returns: BOOLEAN - TRUE if successful, FALSE if unsuccessful.
  515. * Author: shouse, 3.29.01
  516. * Notes: This function acquires the global teaming lock.
  517. */
  518. BOOLEAN Main_teaming_init (IN PMAIN_CTXT ctxtp) {
  519. PBDA_TEAM team;
  520. UNIV_PRINT(("Main_teaming_init: Entering..."));
  521. NdisAcquireSpinLock(&univ_bda_teaming_lock);
  522. /* If the parameters are invalid, do nothing. */
  523. if (!ctxtp->params_valid) {
  524. UNIV_PRINT(("Main_teaming_init: Parameters are invalid. Exiting..."));
  525. NdisReleaseSpinLock(&univ_bda_teaming_lock);
  526. return TRUE;
  527. }
  528. /* Check to see if the state of teaming has changed. If we were actively teaming
  529. before and we are still part of a team, then we may be able to get out of here
  530. without disturbing anything, if the rest of the configuration hasn't changed. */
  531. if (ctxtp->bda_teaming.active == ctxtp->params.bda_teaming.active) {
  532. if (ctxtp->bda_teaming.active) {
  533. /* Make sure that I have a pointer to my team. */
  534. ASSERT(ctxtp->bda_teaming.bda_team);
  535. /* If all other teaming parameters are unchanged, then we can bail out
  536. because no part of the teaming configuration changed. */
  537. if ((ctxtp->bda_teaming.master == ctxtp->params.bda_teaming.master) &&
  538. (ctxtp->bda_teaming.reverse_hash == ctxtp->params.bda_teaming.reverse_hash) &&
  539. NdisEqualMemory((PVOID)ctxtp->bda_teaming.bda_team->team_id, (PVOID)ctxtp->params.bda_teaming.team_id, sizeof(WCHAR) * CVY_MAX_BDA_TEAM_ID)) {
  540. NdisReleaseSpinLock(&univ_bda_teaming_lock);
  541. return TRUE;
  542. }
  543. } else {
  544. /* If I wasn't teaming before, and I'm not teaming now, there's nothing for me to do. */
  545. NdisReleaseSpinLock(&univ_bda_teaming_lock);
  546. return TRUE;
  547. }
  548. }
  549. /* If this adapter is already in a team, cleanup first. At this point, we know that
  550. some part of the teaming configuration has changed, so we'll cleanup our old state
  551. if we need to and then re-build it with the new parameters if necessary. */
  552. if (ctxtp->bda_teaming.active) {
  553. UNIV_PRINT(("Main_teaming_init: This adapter is already part of a team."));
  554. NdisReleaseSpinLock(&univ_bda_teaming_lock);
  555. /* Cleanup our old teaming state first. */
  556. Main_teaming_cleanup(ctxtp);
  557. NdisAcquireSpinLock(&univ_bda_teaming_lock);
  558. }
  559. /* If, according to the new configuration, this adapter is not part of a team, do nothing. */
  560. if (!ctxtp->params.bda_teaming.active) {
  561. UNIV_PRINT(("Main_teaming_init: This adapter is not part of a team. Exiting..."));
  562. ctxtp->bda_teaming.member_id = CVY_BDA_INVALID_MEMBER_ID;
  563. NdisReleaseSpinLock(&univ_bda_teaming_lock);
  564. return TRUE;
  565. }
  566. /* Try to find a previous instance of this team. If the team does not
  567. exist, Main_get_team will allocate, intialize and reference a new team. */
  568. if (!(team = Main_get_team(ctxtp, ctxtp->params.bda_teaming.team_id))) {
  569. UNIV_PRINT(("Main_teaming_init: Error attempting to allocate memory for a team. Exiting..."));
  570. NdisReleaseSpinLock(&univ_bda_teaming_lock);
  571. return FALSE;
  572. }
  573. /* If we are supposed to be the master for this team, we need to make sure that the
  574. team doesn't already have a master, and if so, setup the shared load context. */
  575. if (ctxtp->params.bda_teaming.master) {
  576. /* If we are supposed to be the master for this team, check for an existing master. */
  577. if (team->load) {
  578. /* If the load pointer is set, then this team already has a master. */
  579. UNIV_PRINT(("Main_teaming_init: This team already has a master. Exiting..."));
  580. LOG_MSG(MSG_INFO_BDA_MULTIPLE_MASTERS, MSG_NONE);
  581. /* Release our reference on this team. */
  582. Main_put_team(ctxtp, team);
  583. NdisReleaseSpinLock(&univ_bda_teaming_lock);
  584. return FALSE;
  585. } else {
  586. /* Otherwise, we are it. Set the global load state pointers
  587. to our load module and load lock. */
  588. team->load = &ctxtp->load;
  589. team->load_lock = &ctxtp->load_lock;
  590. /* If all members of my team are consistent, then activate the team. */
  591. if (team->membership_map == team->consistency_map) team->active = TRUE;
  592. /* Log the fact that a master has now been assigned to this team. */
  593. LOG_MSG(MSG_INFO_BDA_MASTER_JOIN, MSG_NONE);
  594. }
  595. }
  596. /* If we have just joined a team without a master, log an event to notify
  597. the user that a team cannot function without a designated master. */
  598. if (!team->load) {
  599. LOG_MSG(MSG_INFO_BDA_NO_MASTER, MSG_NONE);
  600. }
  601. /* Store a pointer to the team in the adapter's teaming context. */
  602. ctxtp->bda_teaming.bda_team = team;
  603. /* Copy the teaming configuration from the parameters into the teaming context. */
  604. ctxtp->bda_teaming.master = ctxtp->params.bda_teaming.master;
  605. ctxtp->bda_teaming.reverse_hash = ctxtp->params.bda_teaming.reverse_hash;
  606. ctxtp->bda_teaming.active = TRUE;
  607. NdisReleaseSpinLock(&univ_bda_teaming_lock);
  608. UNIV_PRINT(("Main_teaming_init: Exiting..."));
  609. return TRUE;
  610. }
  611. /*
  612. * Function: Main_teaming_acquire_load
  613. * Description: This function determines which load module a particular adapter should be unsing,
  614. * sets the appropriate pointers, and references the appropriate load module. If an
  615. * adapter is not part of a BDA team, then it should always be using its own load
  616. * module - in that case, this function does nothing. If the adapter is part of a
  617. * team, but the team in inactive, we return FALSE to indicate that the adapter should
  618. * not accept this packet - inactive teams drop all traffic except traffic to the DIP.
  619. * If the adapter is part of an active team, then we set the load and lock pointers to
  620. * point to the team's master load state and appropriately set the reverse hashing
  621. * indication based on the parameter setting for this adapter. In this scenario, which
  622. * creates a cross-adapter load reference, we reference the master's load module so
  623. * that it doesn't go away while we are using a pointer to it.
  624. * Parameters: member - a pointer to the teaming member information for this adapter.
  625. * ppLoad - an out pointer to a pointer to a load module set appropriately upon exit.
  626. * ppLock - an out pointer to a pointer to a load lock set appropriately upon exit.
  627. * pbTeaming - an out pointer to a boolean that we set if this adapter is teaming.
  628. * pbReverse - an out pointer to a boolean that we set if this adapter is teaming.
  629. * Returns: BOOLEAN - an indication of whether or not this packet is refused (TRUE = drop it).
  630. * Author: shouse, 3.29.01
  631. * Notes: This function acquires the global teaming lock.
  632. */
  633. BOOLEAN Main_teaming_acquire_load (IN PBDA_MEMBER member, OUT PLOAD_CTXT * ppLoad, OUT PNDIS_SPIN_LOCK * ppLock, OUT BOOLEAN * pbTeaming, OUT ULONG * pbReverse) {
  634. NdisAcquireSpinLock(&univ_bda_teaming_lock);
  635. /* Assert that the team membership information actually points to something. */
  636. ASSERT(member);
  637. /* Assert that the load pointer and the pointer to the load pointer actually point to something. */
  638. ASSERT(ppLoad && *ppLoad);
  639. /* Assert that the lock pointer and the pointer to the lock pointer actually point to something. */
  640. ASSERT(ppLock && *ppLock);
  641. /* Assert that the reverse hashing pointer actually points to something. */
  642. ASSERT(pbReverse);
  643. /* Assert that the teaming pointer actually points to something. */
  644. ASSERT(pbTeaming);
  645. /* If we are an active BDA team participant, check the team state to see whether we
  646. should accept this packet and fill in the load module/configuration parameters. */
  647. if (member->active) {
  648. PBDA_TEAM team = member->bda_team;
  649. /* Assert that the team actually points to something. */
  650. ASSERT(team);
  651. /* If the team is inactive, we will not handle this packet. */
  652. if (!team->active) {
  653. NdisReleaseSpinLock(&univ_bda_teaming_lock);
  654. return TRUE;
  655. }
  656. /* Otherwise, tell the caller to use the team's load lock and module. */
  657. *ppLoad = team->load;
  658. *ppLock = team->load_lock;
  659. /* Fill in the reverse-hashing flag and tell the caller that it is indeed teaming. */
  660. *pbReverse = member->reverse_hash;
  661. *pbTeaming = TRUE;
  662. /* In the case of cross-adapter load module reference, add a reference to
  663. the load module we are going to use to keep it from disappering on us. */
  664. Load_add_reference(*ppLoad);
  665. }
  666. NdisReleaseSpinLock(&univ_bda_teaming_lock);
  667. return FALSE;
  668. }
  669. /*
  670. * Function: Main_teaming_release_load
  671. * Description: This function releases a reference to a load module if necessary. If we did not
  672. * acquire this load module pointer in teaming mode, then this is unnessary. Other-
  673. * wise, we need to decrement the count, now that we are done using the pointer.
  674. * Parameters: pLoad - a pointer to the load module to dereference.
  675. * pLock - a pointer to the load lock corresponding to the load module pointer (unused).
  676. * bTeaming - a boolean indication of whether or not we acquired this pointer in teaming mode.
  677. * Returns: Nothing.
  678. * Author: shouse, 3.29.01
  679. * Notes:
  680. */
  681. VOID Main_teaming_release_load (IN PLOAD_CTXT pLoad, IN PNDIS_SPIN_LOCK pLock, IN BOOLEAN bTeaming) {
  682. /* Assert that the load pointer actually points to something. */
  683. ASSERT(pLoad);
  684. /* Assert that the lock pointer actually points to something. */
  685. ASSERT(pLock);
  686. /* If this load module was referenced, remove the reference. */
  687. if (bTeaming) Load_release_reference(pLoad);
  688. }
  689. /*
  690. * Function: Main_packet_check
  691. * Description: This function is, for all intents and purposed, a teaming-aware wrapper
  692. * around Load_packet_check. It determines which load module to utilize,
  693. * based on the BDA teaming configuration on this adapter. Adapters that
  694. * are not part of a team continue to use their own load modules (Which is
  695. * BY FAR, the most common case). Adapters that are part of a team will
  696. * use the load context of the adapter configured as the team's master as
  697. * long as the team is in an active state. In such as case, because of
  698. * the cross-adapter referencing of load modules, the reference count on
  699. * the master's load module is incremented to keep it from "going away"
  700. * while another team member is using it. When a team is marke inactive,
  701. * which is the result of a misconfigured team either on this host or
  702. * another host in the cluster, the adapter handles NO traffic that would
  703. * require the use of a load module. Other traffic, such as traffic to
  704. * the DIP, or RAW IP traffic, is allowed to pass.
  705. * Parameters: ctxtp - a pointer to the MAIN_CTXT structure for this adapter.
  706. * svr_addr - the server IP address (source IP on send, destination IP on recv).
  707. * svr_port - the server port (source port on send, destination port on recv).
  708. * clt_addr - the client IP address (detination IP on send, source IP on recv).
  709. * clt_port - the client port (destination port on send, source port on recv).
  710. * protocol - the protocol for this packet.
  711. * pbRefused - an out parameter to indicate whether BDA teaming has refused service.
  712. * bFilterTeamingOnly - TRUE indicates that this packet should be filtered only if BDA teaming.
  713. * Returns: BOOLEAN - indication of whether or not to accept the packet.
  714. * Author: shouse, 3.29.01
  715. * Notes:
  716. */
  717. __inline BOOLEAN Main_packet_check (PMAIN_CTXT ctxtp,
  718. ULONG svr_addr,
  719. ULONG svr_port,
  720. ULONG clt_addr,
  721. ULONG clt_port,
  722. USHORT protocol,
  723. BOOLEAN * pbRefused,
  724. BOOLEAN bFilterTeamingOnly)
  725. {
  726. /* For BDA teaming, initialize load pointer, lock pointer, reverse hashing flag and teaming flag
  727. assuming that we are not teaming. Main_teaming_acquire_load will change them appropriately. */
  728. PLOAD_CTXT pLoad = &ctxtp->load;
  729. PNDIS_SPIN_LOCK pLock = &ctxtp->load_lock;
  730. ULONG bReverse = FALSE;
  731. BOOLEAN bTeaming = FALSE;
  732. BOOLEAN acpt = TRUE;
  733. /* We check whether or not we are teaming without grabbing the global teaming
  734. lock in an effort to minimize the common case - teaming is a special mode
  735. of operation that is only really useful in a clustered firewall scenario.
  736. So, if we don't think we're teaming, don't bother to check for sure, just
  737. use our own load module and go with it - in the worst case, we handle a
  738. packet we perhaps shouldn't have while we were joining a team or changing
  739. our current team configuration. */
  740. if (ctxtp->bda_teaming.active) {
  741. /* Check the teaming configuration and add a reference to the load module before consulting the load
  742. module. If the return value is TRUE, then the load module was NOT referenced, so we can bail out. */
  743. *pbRefused = Main_teaming_acquire_load(&ctxtp->bda_teaming, &pLoad, &pLock, &bTeaming, &bReverse);
  744. /* If teaming has suggested that we not allow this packet to pass, dump it. */
  745. if (*pbRefused) return FALSE;
  746. }
  747. if (!bTeaming && bFilterTeamingOnly) {
  748. /* If we are only supposed to filter this packet if we are in a BDA team,
  749. then if we are not, we can just return TRUE now to indicate that it is
  750. OK to allow the packet to pass. */
  751. return TRUE;
  752. }
  753. NdisAcquireSpinLock(pLock);
  754. /* If this adapter is reverse hashing, then simply flip the source and
  755. destination IP addresses and ports when sending them to the load module. */
  756. if (bReverse)
  757. acpt = Load_packet_check(pLoad, clt_addr, clt_port, svr_addr, svr_port, protocol, bTeaming);
  758. else
  759. acpt = Load_packet_check(pLoad, svr_addr, svr_port, clt_addr, clt_port, protocol, bTeaming);
  760. NdisReleaseSpinLock(pLock);
  761. /* Release the reference on the load module if necessary. If we aren't teaming, even in
  762. the case we skipped calling Main_teaming_Acquire_load_module above bTeaming is FALSE,
  763. so there is no need to call this function to release a reference. */
  764. if (bTeaming) Main_teaming_release_load(pLoad, pLock, bTeaming);
  765. return acpt;
  766. }
  767. /*
  768. * Function: Main_conn_advise
  769. * Description: This function is, for all intents and purposed, a teaming-aware wrapper
  770. * around Load_conn_advise. It determines which load module to utilize,
  771. * based on the BDA teaming configuration on this adapter. Adapters that
  772. * are not part of a team continue to use their own load modules (Which is
  773. * BY FAR, the most common case). Adapters that are part of a team will
  774. * use the load context of the adapter configured as the team's master as
  775. * long as the team is in an active state. In such as case, because of
  776. * the cross-adapter referencing of load modules, the reference count on
  777. * the master's load module is incremented to keep it from "going away"
  778. * while another team member is using it. When a team is marke inactive,
  779. * which is the result of a misconfigured team either on this host or
  780. * another host in the cluster, the adapter handles NO traffic that would
  781. * require the use of a load module. Other traffic, such as traffic to
  782. * the DIP, or RAW IP traffic, is allowed to pass.
  783. * Parameters: ctxtp - a pointer to the MAIN_CTXT structure for this adapter.
  784. * svr_addr - the server IP address (source IP on send, destination IP on recv).
  785. * svr_port - the server port (source port on send, destination port on recv).
  786. * clt_addr - the client IP address (detination IP on send, source IP on recv).
  787. * clt_port - the client port (destination port on send, source port on recv).
  788. * protocol - the protocol for this packet.
  789. * conn_status - the TCP flag in this packet - SYN (UP), FIN (DOWN) or RST (RESET).
  790. * pbRefused - an out parameter to indicate whether BDA teaming has refused service.
  791. * bFilterTeamingOnly - TRUE indicates that this packet should be filtered only if BDA teaming.
  792. * Returns: BOOLEAN - indication of whether or not to accept the packet.
  793. * Author: shouse, 3.29.01
  794. * Notes:
  795. */
  796. __inline BOOLEAN Main_conn_advise (PMAIN_CTXT ctxtp,
  797. ULONG svr_addr,
  798. ULONG svr_port,
  799. ULONG clt_addr,
  800. ULONG clt_port,
  801. USHORT protocol,
  802. ULONG conn_status,
  803. BOOLEAN * pbRefused,
  804. BOOLEAN bFilterTeamingOnly)
  805. {
  806. /* For BDA teaming, initialize load pointer, lock pointer, reverse hashing flag and teaming flag
  807. assuming that we are not teaming. Main_teaming_acquire_load will change them appropriately. */
  808. PLOAD_CTXT pLoad = &ctxtp->load;
  809. PNDIS_SPIN_LOCK pLock = &ctxtp->load_lock;
  810. ULONG bReverse = FALSE;
  811. BOOLEAN bTeaming = FALSE;
  812. BOOLEAN acpt = TRUE;
  813. /* We check whether or not we are teaming without grabbing the global teaming
  814. lock in an effort to minimize the common case - teaming is a special mode
  815. of operation that is only really useful in a clustered firewall scenario.
  816. So, if we don't think we're teaming, don't bother to check for sure, just
  817. use our own load module and go with it - in the worst case, we handle a
  818. packet we perhaps shouldn't have while we were joining a team or changing
  819. our current team configuration. */
  820. if (ctxtp->bda_teaming.active) {
  821. /* Check the teaming configuration and add a reference to the load module before consulting the load
  822. module. If the return value is TRUE, then the load module was NOT referenced, so we can bail out. */
  823. *pbRefused = Main_teaming_acquire_load(&ctxtp->bda_teaming, &pLoad, &pLock, &bTeaming, &bReverse);
  824. /* If teaming has suggested that we not allow this packet to pass, dump it. */
  825. if (*pbRefused) return FALSE;
  826. }
  827. if (!bTeaming && bFilterTeamingOnly) {
  828. /* If we are only supposed to filter this packet if we are in a BDA team,
  829. then if we are not, we can just return TRUE now to indicate that it is
  830. OK to allow the packet to pass. */
  831. return TRUE;
  832. }
  833. NdisAcquireSpinLock(pLock);
  834. /* If this adapter is reverse hashing, then simply flip the source and
  835. destination IP addresses and ports when sending them to the load module. */
  836. if (bReverse)
  837. acpt = Load_conn_advise(pLoad, clt_addr, clt_port, svr_addr, svr_port, protocol, conn_status, bTeaming);
  838. else
  839. acpt = Load_conn_advise(pLoad, svr_addr, svr_port, clt_addr, clt_port, protocol, conn_status, bTeaming);
  840. NdisReleaseSpinLock(pLock);
  841. /* Release the reference on the load module if necessary. If we aren't teaming, even in
  842. the case we skipped calling Main_teaming_Acquire_load_module above, bTeaming is FALSE,
  843. so there is no need to call this function to release a reference. */
  844. if (bTeaming) Main_teaming_release_load(pLoad, pLock, bTeaming);
  845. return acpt;
  846. }
  847. /*
  848. * Function: Main_create_dscr
  849. * Description: This function is, for all intents and purposed, a teaming-aware wrapper
  850. * around Loas_create_dscr. It determines which load module to utilize,
  851. * based on the BDA teaming configuration on this adapter. Adapters that
  852. * are not part of a team continue to use their own load modules (Which is
  853. * BY FAR, the most common case). Adapters that are part of a team will
  854. * use the load context of the adapter configured as the team's master as
  855. * long as the team is in an active state. In such as case, because of
  856. * the cross-adapter referencing of load modules, the reference count on
  857. * the master's load module is incremented to keep it from "going away"
  858. * while another team member is using it. When a team is marke inactive,
  859. * which is the result of a misconfigured team either on this host or
  860. * another host in the cluster, the adapter handles NO traffic that would
  861. * require the use of a load module. Other traffic, such as traffic to
  862. * the DIP, or RAW IP traffic, is allowed to pass. This function creates
  863. * a connection descriptor in the load module without consulting load-
  864. * balancing state - it is simply a direction, on an outgoing TCP SYN, for
  865. * the load module to create state. Under the restrictions placed on port
  866. * rules in bi-directional affinity teaming, if we create this descriptor
  867. * on the outbound path, we can guarantee that connections originating on
  868. * this NLB host ALWAYS return to this host, even if convergence has
  869. * occurred.
  870. * Parameters: ctxtp - a pointer to the MAIN_CTXT structure for this adapter.
  871. * svr_addr - the server IP address (source IP on send, destination IP on recv).
  872. * svr_port - the server port (source port on send, destination port on recv).
  873. * clt_addr - the client IP address (detination IP on send, source IP on recv).
  874. * clt_port - the client port (destination port on send, source port on recv).
  875. * protocol - the protocol for this packet.
  876. * pbRefused - an out parameter to indicate whether BDA teaming has refused service.
  877. * bFilterTeamingOnly - TRUE indicates that this packet should be filtered only if BDA teaming.
  878. * Returns: BOOLEAN - indication of whether or not to accept the packet (based on the success of descriptor creation).
  879. * Author: shouse, 3.29.01
  880. * Notes:
  881. */
  882. __inline BOOLEAN Main_create_dscr (PMAIN_CTXT ctxtp,
  883. ULONG svr_addr,
  884. ULONG svr_port,
  885. ULONG clt_addr,
  886. ULONG clt_port,
  887. USHORT protocol,
  888. BOOLEAN * pbRefused,
  889. BOOLEAN bFilterTeamingOnly)
  890. {
  891. /* For BDA teaming, initialize load pointer, lock pointer, reverse hashing flag and teaming flag
  892. assuming that we are not teaming. Main_teaming_acquire_load will change them appropriately. */
  893. PLOAD_CTXT pLoad = &ctxtp->load;
  894. PNDIS_SPIN_LOCK pLock = &ctxtp->load_lock;
  895. ULONG bReverse = FALSE;
  896. BOOLEAN bTeaming = FALSE;
  897. BOOLEAN acpt = TRUE;
  898. /* We check whether or not we are teaming without grabbing the global teaming
  899. lock in an effort to minimize the common case - teaming is a special mode
  900. of operation that is only really useful in a clustered firewall scenario.
  901. So, if we don't think we're teaming, don't bother to check for sure, just
  902. use our own load module and go with it - in the worst case, we handle a
  903. packet we perhaps shouldn't have while we were joining a team or changing
  904. our current team configuration. */
  905. if (ctxtp->bda_teaming.active) {
  906. /* Check the teaming configuration and add a reference to the load module before consulting the load module.
  907. If the return value is TRUE, then the load module was NOT referenced, so we can bail out. */
  908. *pbRefused = Main_teaming_acquire_load(&ctxtp->bda_teaming, &pLoad, &pLock, &bTeaming, &bReverse);
  909. /* If teaming has suggested that we not allow this packet to pass, dump it. */
  910. if (*pbRefused) return FALSE;
  911. }
  912. if (!bTeaming && bFilterTeamingOnly) {
  913. /* If we are only supposed to filter this packet if we are in a BDA team,
  914. then if we are not, we can just return TRUE now to indicate that it is
  915. OK to allow the packet to pass. */
  916. return TRUE;
  917. }
  918. /* If we are in a BDA team, then we want to create a descriptor for an outgoing SYN. */
  919. NdisAcquireSpinLock(pLock);
  920. /* If this adapter is reverse hashing, then simply flip the source and
  921. destination IP addresses and ports when sending them to the load module. */
  922. if (bReverse)
  923. acpt = Load_create_dscr(pLoad, clt_addr, clt_port, svr_addr, svr_port, protocol, bTeaming);
  924. else
  925. acpt = Load_create_dscr(pLoad, svr_addr, svr_port, clt_addr, clt_port, protocol, bTeaming);
  926. NdisReleaseSpinLock(pLock);
  927. /* Release the reference on the load module if necessary. If we aren't teaming, even in
  928. the case we skipped calling Main_teaming_Acquire_load_module above, bTeaming is FALSE,
  929. so there is no need to call this function to release a reference. */
  930. if (bTeaming) Main_teaming_release_load(pLoad, pLock, bTeaming);
  931. return acpt;
  932. }
  933. /*
  934. * Function: Main_query_packet_filter
  935. * Desctription:
  936. * Parameters:
  937. * Returns:
  938. * Author: shouse, 5.18.01
  939. * Notes:
  940. */
  941. VOID Main_query_packet_filter (PMAIN_CTXT ctxtp, PIOCTL_QUERY_STATE_PACKET_FILTER pQuery)
  942. {
  943. /* For BDA teaming, initialize load pointer, lock pointer, reverse hashing flag and teaming flag
  944. assuming that we are not teaming. Main_teaming_acquire_load will change them appropriately. */
  945. PLOAD_CTXT pLoad = &ctxtp->load;
  946. PNDIS_SPIN_LOCK pLock = &ctxtp->load_lock;
  947. ULONG bReverse = FALSE;
  948. BOOLEAN bTeaming = FALSE;
  949. BOOLEAN bRefused = FALSE;
  950. BOOLEAN acpt = TRUE;
  951. /* NOTE: This entire operation assumes RECEIVE path semantics - most outgoing traffic
  952. is not filtered by NLB anyway, so there isn't much need to query send filtering. */
  953. /* First check for remote control packets, which are always UDP and are always allowed to pass. */
  954. if (pQuery->Protocol == TCPIP_PROTOCOL_UDP) {
  955. /* If the client UDP port is the remote control port, then this is a remote control
  956. response from another NLB cluster host. These are always allowed to pass. */
  957. if (pQuery->ClientPort == ctxtp->params.rct_port || pQuery->ClientPort == CVY_DEF_RCT_PORT_OLD) {
  958. pQuery->Results.Accept = NLB_ACCEPT_REMOTE_CONTROL_RESPONSE;
  959. return;
  960. /* Otherwise, if the server UDP port is the remote control port, then this is an incoming
  961. remote control request from another NLB cluster host. These are always allowed to pass. */
  962. } else if (pQuery->ServerPort == ctxtp->params.rct_port || pQuery->ServerPort == CVY_DEF_RCT_PORT_OLD) {
  963. pQuery->Results.Accept = NLB_ACCEPT_REMOTE_CONTROL_REQUEST;
  964. return;
  965. }
  966. }
  967. /* Check for traffic destined for the dedicated IP address of this host, or to the cluster
  968. or dedicated broadcast IP addresses. These packets are always allowed to pass. */
  969. if (pQuery->ServerIPAddress == ctxtp->ded_ip_addr || pQuery->ServerIPAddress == ctxtp->ded_bcast_addr || pQuery->ServerIPAddress == ctxtp->cl_bcast_addr) {
  970. pQuery->Results.Accept = NLB_ACCEPT_DIP_OR_BROADCAST;
  971. return;
  972. }
  973. /* Check for passthru packets. When the cluster IP address has not been specified, the
  974. cluster moves into passthru mode, in which it passes up ALL packets received. */
  975. if (ctxtp->cl_ip_addr == 0) {
  976. pQuery->Results.Accept = NLB_ACCEPT_PASSTHRU_MODE;
  977. return;
  978. }
  979. /* If the cluster is not operational, which can happen, for example as a result of a wlbs.exe
  980. command such as "wlbs stop", or as a result of bad parameter settings, then drop all traffic
  981. that does not meet the above conditions. */
  982. if (!ctxtp->convoy_enabled) {
  983. pQuery->Results.Accept = NLB_REJECT_CLUSTER_STOPPED;
  984. return;
  985. }
  986. /* We check whether or not we are teaming without grabbing the global teaming
  987. lock in an effort to minimize the common case - teaming is a special mode
  988. of operation that is only really useful in a clustered firewall scenario.
  989. So, if we don't think we're teaming, don't bother to check for sure, just
  990. use our own load module and go with it - in the worst case, we handle a
  991. packet we perhaps shouldn't have while we were joining a team or changing
  992. our current team configuration. */
  993. if (ctxtp->bda_teaming.active) {
  994. /* Check the teaming configuration and add a reference to the load module before consulting the load
  995. module. If the return value is TRUE, then the load module was NOT referenced, so we can bail out. */
  996. bRefused = Main_teaming_acquire_load(&ctxtp->bda_teaming, &pLoad, &pLock, &bTeaming, &bReverse);
  997. /* If teaming has suggested that we not allow this packet to pass, the cluster will
  998. drop it. This occurs when teams are inconsistently configured, or when a team is
  999. without a master, in which case there is no load context to consult anyway. */
  1000. if (bRefused) {
  1001. pQuery->Results.Accept = NLB_REJECT_BDA_TEAMING_REFUSED;
  1002. return;
  1003. }
  1004. }
  1005. NdisAcquireSpinLock(pLock);
  1006. /* If this adapter is reverse hashing, then simply flip the source and destination IP addresses
  1007. and ports when sending them to the load module. This function will run the NLB hashing
  1008. algorithm using the provided IP tuple and protocol information and fill in the query buffer
  1009. with appropriate hashing and connection descriptor information. */
  1010. if (bReverse)
  1011. Load_query_packet_filter(pQuery, pLoad, pQuery->ClientIPAddress, pQuery->ClientPort, pQuery->ServerIPAddress, pQuery->ServerPort, pQuery->Protocol, bTeaming);
  1012. else
  1013. Load_query_packet_filter(pQuery, pLoad, pQuery->ServerIPAddress, pQuery->ServerPort, pQuery->ClientIPAddress, pQuery->ClientPort, pQuery->Protocol, bTeaming);
  1014. NdisReleaseSpinLock(pLock);
  1015. /* Release the reference on the load module if necessary. If we aren't teaming, even in
  1016. the case we skipped calling Main_teaming_Acquire_load_module above, bTeaming is FALSE,
  1017. so there is no need to call this function to release a reference. */
  1018. if (bTeaming) Main_teaming_release_load(pLoad, pLock, bTeaming);
  1019. }
  1020. ULONG Main_ip_addr_init (
  1021. PMAIN_CTXT ctxtp)
  1022. {
  1023. ULONG byte [4];
  1024. ULONG i;
  1025. PWCHAR tmp;
  1026. ULONG old_ip_addr;
  1027. /* initialize dedicated IP address from the register string */
  1028. tmp = ctxtp -> params . ded_ip_addr;
  1029. ctxtp -> ded_ip_addr = 0;
  1030. /* do not initialize if one was not specified */
  1031. if (tmp [0] == 0)
  1032. goto ded_netmask;
  1033. for (i = 0; i < 4; i ++)
  1034. {
  1035. if (! Univ_str_to_ulong (byte + i, tmp, & tmp, 3, 10) ||
  1036. (i < 3 && * tmp != L'.'))
  1037. {
  1038. UNIV_PRINT (("bad dedicated IP address"));
  1039. LOG_MSG (MSG_WARN_DED_IP_ADDR, ctxtp -> params . ded_ip_addr);
  1040. ctxtp -> ded_net_mask = 0;
  1041. goto ded_netmask;
  1042. }
  1043. tmp ++;
  1044. }
  1045. IP_SET_ADDR (& ctxtp -> ded_ip_addr, byte [0], byte [1], byte [2], byte [3]);
  1046. UNIV_PRINT (("Dedicated IP address: %d.%d.%d.%d = %x", byte [0], byte [1], byte [2], byte [3], ctxtp -> ded_ip_addr));
  1047. ded_netmask:
  1048. /* initialize dedicated net mask from the register string */
  1049. tmp = ctxtp -> params . ded_net_mask;
  1050. ctxtp -> ded_net_mask = 0;
  1051. /* do not initialize if one was not specified */
  1052. if (tmp [0] == 0)
  1053. goto cluster;
  1054. for (i = 0; i < 4; i ++)
  1055. {
  1056. if (! Univ_str_to_ulong (byte + i, tmp, & tmp, 3, 10) ||
  1057. (i < 3 && * tmp != L'.'))
  1058. {
  1059. UNIV_PRINT (("bad dedicated net mask address"));
  1060. LOG_MSG (MSG_WARN_DED_NET_MASK, ctxtp -> params . ded_net_mask);
  1061. ctxtp -> ded_ip_addr = 0;
  1062. goto cluster;
  1063. }
  1064. tmp ++;
  1065. }
  1066. IP_SET_ADDR (& ctxtp -> ded_net_mask, byte [0], byte [1], byte [2], byte [3]);
  1067. UNIV_PRINT (("Dedicated net mask: %d.%d.%d.%d = %x", byte [0], byte [1], byte [2], byte [3], ctxtp -> ded_net_mask));
  1068. cluster:
  1069. /* initialize cluster IP address from the register string */
  1070. tmp = ctxtp -> params . cl_ip_addr;
  1071. /* Save the previous cluster IP address to notify bi-directional affinity teaming. */
  1072. old_ip_addr = ctxtp -> cl_ip_addr;
  1073. ctxtp -> cl_ip_addr = 0;
  1074. for (i = 0; i < 4; i ++)
  1075. {
  1076. if (! Univ_str_to_ulong (byte + i, tmp, & tmp, 3, 10) ||
  1077. (i < 3 && * tmp != L'.'))
  1078. {
  1079. UNIV_PRINT (("bad cluster IP address"));
  1080. LOG_MSG (MSG_ERROR_CL_IP_ADDR, ctxtp -> params . cl_ip_addr);
  1081. ctxtp -> cl_net_mask = 0;
  1082. return FALSE;
  1083. }
  1084. tmp ++;
  1085. }
  1086. IP_SET_ADDR (& ctxtp -> cl_ip_addr, byte [0], byte [1], byte [2], byte [3]);
  1087. UNIV_PRINT (("Cluster IP address: %d.%d.%d.%d = %x", byte [0], byte [1], byte [2], byte [3], ctxtp -> cl_ip_addr));
  1088. /* Notify BDA teaming config that a cluster IP address might have changed. */
  1089. Main_teaming_ip_addr_change(ctxtp, old_ip_addr, ctxtp->cl_ip_addr);
  1090. /* initialize cluster net mask from the register string */
  1091. tmp = ctxtp -> params . cl_net_mask;
  1092. ctxtp -> cl_net_mask = 0;
  1093. /* do not initialize if one was not specified */
  1094. for (i = 0; i < 4; i ++)
  1095. {
  1096. if (! Univ_str_to_ulong (byte + i, tmp, & tmp, 3, 10) ||
  1097. (i < 3 && * tmp != L'.'))
  1098. {
  1099. UNIV_PRINT (("bad cluster net mask address"));
  1100. LOG_MSG (MSG_ERROR_CL_NET_MASK, ctxtp -> params . cl_net_mask);
  1101. return FALSE;
  1102. }
  1103. tmp ++;
  1104. }
  1105. IP_SET_ADDR (& ctxtp -> cl_net_mask, byte [0], byte [1], byte [2], byte [3]);
  1106. UNIV_PRINT (("Cluster net mask: %d.%d.%d.%d = %x", byte [0], byte [1], byte [2], byte [3], ctxtp -> cl_net_mask));
  1107. if (ctxtp -> params . mcast_support && ctxtp -> params . igmp_support)
  1108. {
  1109. /* Initialize the multicast IP address for IGMP support */
  1110. tmp = ctxtp -> params . cl_igmp_addr;
  1111. ctxtp -> cl_igmp_addr = 0;
  1112. /* do not initialize if one was not specified */
  1113. for (i = 0; i < 4; i ++)
  1114. {
  1115. if (! Univ_str_to_ulong (byte + i, tmp, & tmp, 3, 10) ||
  1116. (i < 3 && * tmp != L'.'))
  1117. {
  1118. UNIV_PRINT (("bad cluster net mask address"));
  1119. // LOG_MSG (MSG_ERROR_CL_NET_MASK, ctxtp -> params . cl_igmp_addr); // is this required since it is checked in the APIs?
  1120. return FALSE;
  1121. }
  1122. tmp ++;
  1123. }
  1124. IP_SET_ADDR (& ctxtp -> cl_igmp_addr, byte [0], byte [1], byte [2], byte [3]);
  1125. UNIV_PRINT (("Cluster IGMP Address: %d.%d.%d.%d = %x", byte [0], byte [1], byte [2], byte [3], ctxtp -> cl_igmp_addr));
  1126. }
  1127. if ((ctxtp -> ded_ip_addr != 0 && ctxtp -> ded_net_mask == 0) ||
  1128. (ctxtp -> ded_ip_addr == 0 && ctxtp -> ded_net_mask != 0))
  1129. {
  1130. UNIV_PRINT (("need to specify both dedicated IP address AND network mask"));
  1131. LOG_MSG (MSG_WARN_DED_MISMATCH, MSG_NONE);
  1132. ctxtp -> ded_ip_addr = 0;
  1133. ctxtp -> ded_net_mask = 0;
  1134. }
  1135. IP_SET_BCAST (& ctxtp -> cl_bcast_addr, ctxtp -> cl_ip_addr, ctxtp -> cl_net_mask);
  1136. UNIV_PRINT (("Cluster broadcast address: %d.%d.%d.%d = %x", ctxtp -> cl_bcast_addr & 0xff, (ctxtp -> cl_bcast_addr >> 8) & 0xff, (ctxtp -> cl_bcast_addr >> 16) & 0xff, (ctxtp -> cl_bcast_addr >> 24) & 0xff, ctxtp -> cl_bcast_addr));
  1137. if (ctxtp -> ded_ip_addr != 0)
  1138. {
  1139. IP_SET_BCAST (& ctxtp -> ded_bcast_addr, ctxtp -> ded_ip_addr, ctxtp -> ded_net_mask);
  1140. UNIV_PRINT (("Dedicated broadcast address: %d.%d.%d.%d = %x", ctxtp -> ded_bcast_addr & 0xff, (ctxtp -> ded_bcast_addr >> 8) & 0xff, (ctxtp -> ded_bcast_addr >> 16) & 0xff, (ctxtp -> ded_bcast_addr >> 24) & 0xff, ctxtp -> ded_bcast_addr));
  1141. }
  1142. else
  1143. ctxtp -> ded_bcast_addr = 0;
  1144. if (ctxtp -> cl_ip_addr == 0)
  1145. {
  1146. UNIV_PRINT (("Cluster IP address = 0. Cluster host stopped"));
  1147. return FALSE;
  1148. }
  1149. return TRUE;
  1150. } /* end Main_ip_addr_init */
  1151. ULONG Main_mac_addr_init (
  1152. PMAIN_CTXT ctxtp)
  1153. {
  1154. ULONG i, b, len;
  1155. PUCHAR ap;
  1156. PWCHAR tmp;
  1157. PUCHAR srcp, dstp;
  1158. ULONG non_zero = 0;
  1159. CVY_MAC_ADR old_mac_addr;
  1160. /* remember old mac address so we can yank it out of the multicast list */
  1161. old_mac_addr = ctxtp->cl_mac_addr;
  1162. /* at the time this routine is called by Prot_bind - ded_mad_addr is
  1163. already set */
  1164. tmp = ctxtp -> params . cl_mac_addr;
  1165. len = CVY_MAC_ADDR_LEN (ctxtp -> medium);
  1166. ap = (PUCHAR) & ctxtp -> cl_mac_addr;
  1167. for (i = 0; i < len; i ++)
  1168. {
  1169. /* setup destination broadcast and source cluster addresses */
  1170. if (! Univ_str_to_ulong (& b, tmp, & tmp, 2, 16) ||
  1171. (i < len - 1 && * tmp != L'-' && * tmp != L':'))
  1172. {
  1173. UNIV_PRINT (("bad cluster network address"));
  1174. LOG_MSG (MSG_ERROR_NET_ADDR, ctxtp -> params . cl_mac_addr);
  1175. /* WLBS 2.3 prevent from failing if no MAC address - just use the
  1176. dedicated one as cluster */
  1177. NdisMoveMemory (& ctxtp -> cl_mac_addr, & ctxtp -> ded_mac_addr, len);
  1178. non_zero = 1;
  1179. break;
  1180. }
  1181. tmp ++;
  1182. ap [i] = (UCHAR) b;
  1183. /* WLBS 2.3 sum up bytes for future non-zero check */
  1184. non_zero += b;
  1185. }
  1186. /* WLBS 2.3 - use dedicated address as cluster address if specified address
  1187. is zero - this could be due to parameter errors */
  1188. if (non_zero == 0)
  1189. NdisMoveMemory (& ctxtp -> cl_mac_addr, & ctxtp -> ded_mac_addr, len);
  1190. /* enforce group flag to proper value */
  1191. if (ctxtp -> params . mcast_support)
  1192. ap [0] |= ETHERNET_GROUP_FLAG;
  1193. else
  1194. ap [0] &= ~ETHERNET_GROUP_FLAG;
  1195. if (ctxtp -> medium == NdisMedium802_3)
  1196. {
  1197. dstp = ctxtp -> media_hdr . ethernet . dst . data;
  1198. srcp = ctxtp -> media_hdr . ethernet . src . data;
  1199. len = ETHERNET_ADDRESS_FIELD_SIZE;
  1200. CVY_ETHERNET_ETYPE_SET (& ctxtp -> media_hdr . ethernet, MAIN_FRAME_SIG);
  1201. }
  1202. ctxtp -> etype_old = FALSE;
  1203. /* V1.3.1b - load multicast address as destination instead of broadcast */
  1204. for (i = 0; i < len; i ++)
  1205. {
  1206. if (ctxtp -> params . mcast_support)
  1207. dstp [i] = ap [i];
  1208. else
  1209. dstp [i] = 0xff;
  1210. srcp [i] = ((PUCHAR) & ctxtp -> ded_mac_addr) [i];
  1211. }
  1212. if (! ctxtp -> params . mcast_support)
  1213. {
  1214. /* V2.0.6 - override source MAC address to prevent switch confusion */
  1215. if (ctxtp -> params . mask_src_mac)
  1216. {
  1217. CVY_MAC_ADDR_LAA_SET (ctxtp -> medium, srcp);
  1218. * ((PUCHAR) (srcp + 1)) = (UCHAR) ctxtp -> params . host_priority;
  1219. * ((PULONG) (srcp + 2)) = ctxtp -> cl_ip_addr;
  1220. }
  1221. /* make source address look difference than our dedicated to prevent
  1222. Compaq drivers from optimizing their reception out */
  1223. else
  1224. CVY_MAC_ADDR_LAA_TOGGLE (ctxtp -> medium, srcp);
  1225. }
  1226. #if defined (NLB_MIXED_MODE_CLUSTERS)
  1227. PUCHAR s,d;
  1228. len = CVY_MAC_ADDR_LEN (ctxtp -> medium);
  1229. /* derive the unicast mac address */
  1230. s = (PUCHAR) (& (ctxtp -> unic_mac_addr));
  1231. s[0] = 0x02;
  1232. s[1] = 0xbf;
  1233. s[2] = (UCHAR) (ctxtp -> cl_ip_addr & 0xff);
  1234. s[3] = (UCHAR) ((ctxtp -> cl_ip_addr & 0xff00) >> 8);
  1235. s[4] = (UCHAR) ((ctxtp -> cl_ip_addr & 0xff0000) >> 16);
  1236. s[5] = (UCHAR) ((ctxtp -> cl_ip_addr & 0xff000000) >> 24);
  1237. /* derive the multicast mac address */
  1238. NdisMoveMemory ( & ctxtp -> mult_mac_addr, & ctxtp -> unic_mac_addr, len);
  1239. d = (PUCHAR) (& (ctxtp -> mult_mac_addr));
  1240. d[0] = 0x03;
  1241. /* derive the igmp mac address */
  1242. NdisMoveMemory ( & ctxtp -> igmp_mac_addr, & ctxtp -> unic_mac_addr, len);
  1243. d = (PUCHAR) (& (ctxtp -> igmp_mac_addr));
  1244. d[0] = 0x01;
  1245. d[1] = 0x00;
  1246. d[2] = 0x5e;
  1247. d[3] = 0x7f;
  1248. CVY_MAC_ADDR_PRINT (ctxtp -> medium, "Unicast mac address: ", (PUCHAR) & ctxtp -> unic_mac_addr);
  1249. CVY_MAC_ADDR_PRINT (ctxtp -> medium, "Multicast mac address: ", (PUCHAR) & ctxtp -> mult_mac_addr);
  1250. CVY_MAC_ADDR_PRINT (ctxtp -> medium, "IGMP mac address: ", (PUCHAR) & ctxtp -> igmp_mac_addr);
  1251. #endif /* NLB_MIXED_MODE_CLUSTERS */
  1252. CVY_MAC_ADDR_PRINT (ctxtp -> medium, "Cluster network address: ", ap);
  1253. CVY_MAC_ADDR_PRINT (ctxtp -> medium, "Dedicated network address: ", srcp);
  1254. /* Load cluster address as multicast one to the NIC. If the cluster IP address 0.0.0.0, then we
  1255. don't want to add the multicast MAC address to the NIC - we retain the current MAC address. */
  1256. if (ctxtp -> params . mcast_support && ctxtp -> params . cl_ip_addr != 0)
  1257. {
  1258. ULONG xferred;
  1259. ULONG needed;
  1260. PNDIS_REQUEST request;
  1261. MAIN_ACTION act;
  1262. PUCHAR ptr;
  1263. NDIS_STATUS status;
  1264. ULONG size, i, len;
  1265. len = CVY_MAC_ADDR_LEN (ctxtp->medium);
  1266. size = ctxtp->max_mcast_list_size * len;
  1267. status = NdisAllocateMemoryWithTag (& ptr, size, UNIV_POOL_TAG);
  1268. if (status != NDIS_STATUS_SUCCESS)
  1269. {
  1270. UNIV_PRINT (("error allocating space %d %x", size, status));
  1271. LOG_MSG2 (MSG_ERROR_MEMORY, MSG_NONE, size, status);
  1272. return FALSE;
  1273. }
  1274. act . code = MAIN_ACTION_CODE;
  1275. act . ctxtp = ctxtp;
  1276. request = & act . op . request . req;
  1277. act . op . request . xferred = & xferred;
  1278. act . op . request . needed = & needed;
  1279. /* get current mcast list */
  1280. request -> RequestType = NdisRequestQueryInformation;
  1281. if (ctxtp -> medium == NdisMedium802_3)
  1282. request -> DATA . QUERY_INFORMATION . Oid = OID_802_3_MULTICAST_LIST;
  1283. request -> DATA . QUERY_INFORMATION . InformationBufferLength = size;
  1284. request -> DATA . QUERY_INFORMATION . InformationBuffer = ptr;
  1285. status = Prot_request (ctxtp, & act, FALSE);
  1286. if (status != NDIS_STATUS_SUCCESS)
  1287. {
  1288. UNIV_PRINT (("error %x querying multicast address list %d %d", status, xferred, needed));
  1289. NdisFreeMemory (ptr, size, 0);
  1290. return FALSE;
  1291. }
  1292. for (i = 0; i < xferred; i += len)
  1293. {
  1294. if (CVY_MAC_ADDR_COMP (ctxtp -> medium, (PUCHAR) ptr + i, & old_mac_addr))
  1295. {
  1296. UNIV_PRINT (("old cluster MAC matched"));
  1297. CVY_MAC_ADDR_PRINT (ctxtp -> medium, "", & old_mac_addr);
  1298. UNIV_PRINT (("copying new MAC into %dth entry in the multicast list", i));
  1299. CVY_MAC_ADDR_PRINT (ctxtp -> medium, "", & ctxtp->cl_mac_addr);
  1300. CVY_MAC_ADDR_COPY (ctxtp->medium, (PUCHAR) ptr + i, & ctxtp->cl_mac_addr);
  1301. break;
  1302. }
  1303. else
  1304. CVY_MAC_ADDR_PRINT (ctxtp -> medium, "", & ctxtp -> cl_mac_addr);
  1305. }
  1306. /* add MAC if not present */
  1307. if (i >= xferred)
  1308. {
  1309. UNIV_PRINT (("adding new MAC"));
  1310. CVY_MAC_ADDR_PRINT (ctxtp -> medium, "", & ctxtp->cl_mac_addr);
  1311. if (xferred + len > size)
  1312. {
  1313. UNIV_PRINT (("no room for cluster mac %d", ctxtp->max_mcast_list_size));
  1314. LOG_MSG1 (MSG_ERROR_MCAST_LIST_SIZE, L"", ctxtp->max_mcast_list_size);
  1315. NdisFreeMemory (ptr, size, 0);
  1316. return FALSE;
  1317. }
  1318. UNIV_PRINT (("copying new MAC into %dth entry in the multicast list", i));
  1319. CVY_MAC_ADDR_PRINT (ctxtp -> medium, "", & ctxtp->cl_mac_addr);
  1320. CVY_MAC_ADDR_COPY (ctxtp->medium, (PUCHAR) ptr + xferred, & ctxtp->cl_mac_addr);
  1321. xferred += len;
  1322. }
  1323. request -> RequestType = NdisRequestSetInformation;
  1324. if (ctxtp -> medium == NdisMedium802_3)
  1325. request -> DATA . SET_INFORMATION . Oid = OID_802_3_MULTICAST_LIST;
  1326. request -> DATA . SET_INFORMATION . InformationBufferLength = xferred;
  1327. request -> DATA . SET_INFORMATION . InformationBuffer = ptr;
  1328. status = Prot_request (ctxtp, & act, FALSE);
  1329. if (status != NDIS_STATUS_SUCCESS)
  1330. {
  1331. UNIV_PRINT (("error %x setting multicast address %d %d", status, xferred, needed));
  1332. NdisFreeMemory (ptr, size, 0);
  1333. return FALSE;
  1334. }
  1335. NdisFreeMemory (ptr, size, 0);
  1336. }
  1337. return TRUE;
  1338. } /* end Main_mac_addr_init */
  1339. /* Initialize the Ethernet Header and IP packet for sending out IGMP joins/leaves */
  1340. ULONG Main_igmp_init (
  1341. PMAIN_CTXT ctxtp,
  1342. BOOLEAN join)
  1343. {
  1344. PUCHAR ptr;
  1345. ULONG checksum;
  1346. PMAIN_IGMP_DATA igmpd = & (ctxtp -> igmp_frame . igmp_data);
  1347. PMAIN_IP_HEADER iph = & (ctxtp -> igmp_frame . ip_data);
  1348. PUCHAR srcp, dstp;
  1349. UINT i;
  1350. if ((!ctxtp -> params . mcast_support) || (!ctxtp -> params . igmp_support))
  1351. return FALSE;
  1352. /* Fill in the igmp data */
  1353. igmpd -> igmp_vertype = 0x12; /* Needs to be changed for join/leave */
  1354. igmpd -> igmp_unused = 0x00;
  1355. igmpd -> igmp_xsum = 0x0000;
  1356. igmpd -> igmp_address = ctxtp -> cl_igmp_addr;
  1357. /* Compute the IGMP checksum */
  1358. ptr = (PUCHAR) igmpd;
  1359. checksum = 0;
  1360. for (i = 0; i < sizeof (MAIN_IGMP_DATA) / 2; i ++, ptr += 2)
  1361. checksum += (ULONG) ((ptr [0] << 8) | ptr [1]);
  1362. checksum = (checksum >> 16) + (checksum & 0xffff);
  1363. checksum += (checksum >> 16);
  1364. checksum = (~ checksum);
  1365. ptr = (PUCHAR) (& igmpd -> igmp_xsum);
  1366. ptr [0] = (CHAR) ((checksum >> 8) & 0xff);
  1367. ptr [1] = (CHAR) (checksum & 0xff);
  1368. /* Fill in the IP Header */
  1369. iph -> iph_verlen = 0x45;
  1370. iph -> iph_tos = 0;
  1371. iph -> iph_length = 0x1c00;
  1372. iph -> iph_id = 0xabcd; /* Need to find the significance of this later */
  1373. iph -> iph_offset = 0;
  1374. iph -> iph_ttl = 0x1;
  1375. iph -> iph_protocol = 0x2;
  1376. iph -> iph_xsum = 0x0;
  1377. iph -> iph_src = ctxtp -> cl_ip_addr;
  1378. iph -> iph_dest = ctxtp -> cl_igmp_addr;
  1379. /* Compute the checksum for the IP header */
  1380. checksum = Tcpip_chksum (& ctxtp -> tcpip, (PIP_HDR) iph, NULL, TCPIP_PROTOCOL_IP);
  1381. IP_SET_CHKSUM ((PIP_HDR) iph, (USHORT) checksum);
  1382. /* Fill in the ethernet header */
  1383. if (ctxtp -> medium == NdisMedium802_3)
  1384. {
  1385. dstp = ctxtp -> media_hdr_igmp . ethernet . dst . data;
  1386. srcp = ctxtp -> media_hdr_igmp . ethernet . src . data;
  1387. CVY_ETHERNET_ETYPE_SET (& ctxtp -> media_hdr_igmp . ethernet, MAIN_IP_SIG);
  1388. }
  1389. CVY_MAC_ADDR_COPY (ctxtp -> medium, dstp, & ctxtp -> cl_mac_addr);
  1390. CVY_MAC_ADDR_COPY (ctxtp -> medium, srcp, & ctxtp -> ded_mac_addr);
  1391. return TRUE;
  1392. } /* end Main_igmp_init */
  1393. NDIS_STATUS Main_init (
  1394. PMAIN_CTXT ctxtp)
  1395. {
  1396. ULONG i, size;
  1397. NDIS_STATUS status;
  1398. PMAIN_FRAME_DSCR dscrp;
  1399. /* hook the IRP_MJ_DEVICE_CONTROL entry point in order to catch user-mode
  1400. requests to the driver. this is probably a hack, since there has to
  1401. be an IOCTL to NDIS-installed handler that will cause our
  1402. QueryInformationHandler to be called. could not find it in the
  1403. documentation though */
  1404. ioctrl_ctxtp = ctxtp;
  1405. #if 0
  1406. univ_ioctl_hdlr = ((PDRIVER_OBJECT) univ_driver_ptr) -> MajorFunction [IRP_MJ_DEVICE_CONTROL];
  1407. ((PDRIVER_OBJECT) univ_driver_ptr) -> MajorFunction [IRP_MJ_DEVICE_CONTROL] = Main_ioctl;
  1408. #endif
  1409. /* V2.0.6 */
  1410. // UNIV_ASSERT_VAL (sizeof (MAIN_PROTOCOL_RESERVED) <= 16, sizeof (MAIN_PROTOCOL_RESERVED));
  1411. /* V1.3.2b */
  1412. if (sizeof (PING_MSG) + sizeof (MAIN_FRAME_HDR) > ctxtp -> max_frame_size)
  1413. {
  1414. UNIV_PRINT (("ping message will not fit in the media frame %d > %d", sizeof (PING_MSG) + sizeof (MAIN_FRAME_HDR), ctxtp -> max_frame_size));
  1415. LOG_MSG2 (MSG_ERROR_INTERNAL, MSG_NONE, sizeof (PING_MSG) + sizeof (MAIN_FRAME_HDR), ctxtp -> max_frame_size);
  1416. goto error;
  1417. }
  1418. /* V2.0.6 initialize IP addresses - might be used in the Main_mac_addr_init
  1419. so have to do it here */
  1420. if (! Main_ip_addr_init (ctxtp))
  1421. {
  1422. ctxtp -> convoy_enabled = FALSE;
  1423. ctxtp -> params_valid = FALSE;
  1424. UNIV_PRINT (("error initializing IP addresses"));
  1425. }
  1426. /* V1.3.1b parse cluster MAC address from parameters */
  1427. if (! Main_mac_addr_init (ctxtp))
  1428. {
  1429. ctxtp -> convoy_enabled = FALSE;
  1430. ctxtp -> params_valid = FALSE;
  1431. UNIV_PRINT (("error initializing cluster MAC address"));
  1432. }
  1433. /* Initialize IGMP message if in igmp mode */
  1434. if (ctxtp -> params . mcast_support && ctxtp -> params . igmp_support)
  1435. {
  1436. if (! Main_igmp_init (ctxtp, TRUE))
  1437. {
  1438. ctxtp -> convoy_enabled = FALSE;
  1439. ctxtp -> params_valid = FALSE;
  1440. UNIV_PRINT (("error initializing IGMP message"));
  1441. }
  1442. UNIV_PRINT (("IGMP message initialized"));
  1443. }
  1444. /* can extract the send message pointer even if load is not inited yet V1.1.4 */
  1445. ctxtp -> load_msgp = Load_snd_msg_get (& ctxtp -> load);
  1446. /* initalize lists and locks */
  1447. NdisInitializeListHead (& ctxtp -> sync_list[0]);
  1448. NdisInitializeListHead (& ctxtp -> sync_list[1]);
  1449. NdisInitializeListHead (& ctxtp -> act_list);
  1450. NdisInitializeListHead (& ctxtp -> buf_list);
  1451. NdisInitializeListHead (& ctxtp -> frame_list);
  1452. NdisInitializeListHead (& ctxtp -> rct_list);
  1453. NdisAllocateSpinLock (& ctxtp -> sync_lock);
  1454. NdisAllocateSpinLock (& ctxtp -> act_lock);
  1455. NdisAllocateSpinLock (& ctxtp -> buf_lock);
  1456. NdisAllocateSpinLock (& ctxtp -> recv_lock);
  1457. NdisAllocateSpinLock (& ctxtp -> send_lock);
  1458. NdisAllocateSpinLock (& ctxtp -> frame_lock);
  1459. NdisAllocateSpinLock (& ctxtp -> rct_lock);
  1460. NdisAllocateSpinLock (& ctxtp -> load_lock);
  1461. /* #ps# */
  1462. NdisInitializeNPagedLookasideList (& ctxtp -> resp_list, NULL, NULL, 0,
  1463. sizeof (MAIN_PROTOCOL_RESERVED),
  1464. UNIV_POOL_TAG, 0);
  1465. /* capture boot-time parameters */
  1466. ctxtp -> num_packets = ctxtp -> params . num_packets;
  1467. ctxtp -> num_actions = ctxtp -> params . num_actions;
  1468. ctxtp -> num_send_msgs = ctxtp -> params . num_send_msgs;
  1469. #if 0
  1470. /* ###### for tracking pending packets - ramkrish */
  1471. NdisAllocateSpinLock (& ctxtp -> pending_lock);
  1472. ctxtp -> pending_count = 0;
  1473. ctxtp -> pending_first = 0;
  1474. ctxtp -> pending_last = 0;
  1475. ctxtp -> pending_access = 0;
  1476. /* ###### for tracking send filtering - ramkrish */
  1477. ctxtp -> sends_in = 0;
  1478. ctxtp -> sends_completed = 0;
  1479. ctxtp -> sends_filtered = 0;
  1480. ctxtp -> arps_filtered = 0;
  1481. ctxtp -> mac_modified = 0;
  1482. ctxtp -> arps_count = 0;
  1483. ctxtp -> uninited_return = 0;
  1484. #endif
  1485. /* V1.1.1 - initalize other contexts */
  1486. if (! Tcpip_init (& ctxtp -> tcpip, & ctxtp -> params))
  1487. {
  1488. UNIV_PRINT (("error initializing tcpip layer"));
  1489. goto error;
  1490. }
  1491. UNIV_PRINT (("Initialized tcpip"));
  1492. Load_init (& ctxtp -> load, & ctxtp -> params);
  1493. UNIV_PRINT (("Initialized load"));
  1494. /* don't try to init addresses if already encountered error - strings
  1495. could be bad ! */
  1496. if (ctxtp -> params_valid && ctxtp -> params . cluster_mode && ctxtp -> convoy_enabled)
  1497. {
  1498. UNIV_PRINT (("Main_init: calling load_start"));
  1499. Load_start (& ctxtp -> load);
  1500. }
  1501. /* allocate actions */
  1502. size = sizeof (MAIN_ACTION);
  1503. #ifdef _WIN64 // 64-bit -- ramkrish
  1504. ctxtp -> act_size = (size & 0x7) ? (size + 8 - (size & 0x7) ) : size;
  1505. #else
  1506. ctxtp -> act_size = size;
  1507. #endif
  1508. if (! Main_actions_alloc (ctxtp))
  1509. goto error;
  1510. /* V1.3.2b - allocate buffers */
  1511. ctxtp -> buf_mac_hdr_len = CVY_MAC_HDR_LEN (ctxtp -> medium);
  1512. ctxtp -> buf_size = sizeof (MAIN_BUFFER) + ctxtp -> buf_mac_hdr_len +
  1513. ctxtp -> max_frame_size - 1;
  1514. /* 64-bit -- ramkrish */
  1515. UNIV_PRINT (("ctxtp -> buf_size = %d", ctxtp -> buf_size));
  1516. size = ctxtp -> buf_size;
  1517. #ifdef _WIN64
  1518. ctxtp -> buf_size = (size & 0x7) ? (size + 8 - (size & 0x7)) : size;
  1519. UNIV_PRINT (("ctxtp -> buf_size = %d", ctxtp -> buf_size));
  1520. #else
  1521. ctxtp -> buf_size = size;
  1522. #endif
  1523. if (! Main_bufs_alloc (ctxtp))
  1524. goto error;
  1525. size = ctxtp -> num_packets;
  1526. /* V1.1.2 - allocate packet pools */
  1527. NdisAllocatePacketPool (& status, & (ctxtp -> send_pool_handle [0]),
  1528. ctxtp -> num_packets,
  1529. sizeof (MAIN_PROTOCOL_RESERVED));
  1530. if (status != NDIS_STATUS_SUCCESS)
  1531. {
  1532. UNIV_PRINT (("error allocating send packet pool %d %x", size, status));
  1533. LOG_MSG2 (MSG_ERROR_MEMORY, MSG_NONE, size, status);
  1534. goto error;
  1535. }
  1536. ctxtp -> num_send_packet_allocs = 1;
  1537. ctxtp -> cur_send_packet_pool = 0;
  1538. ctxtp -> num_sends_alloced = ctxtp->num_packets;
  1539. NdisAllocatePacketPool (& status, & (ctxtp -> recv_pool_handle [0]),
  1540. ctxtp -> num_packets,
  1541. sizeof (MAIN_PROTOCOL_RESERVED));
  1542. if (status != NDIS_STATUS_SUCCESS)
  1543. {
  1544. UNIV_PRINT (("error allocating recv packet pool %d %x", size, status));
  1545. LOG_MSG2 (MSG_ERROR_MEMORY, MSG_NONE, size, status);
  1546. goto error;
  1547. }
  1548. ctxtp -> num_recv_packet_allocs = 1;
  1549. ctxtp -> cur_recv_packet_pool = 0;
  1550. ctxtp -> num_recvs_alloced = ctxtp->num_packets;
  1551. /* allocate support for heartbeat ping messages */
  1552. size = sizeof (MAIN_FRAME_DSCR) * ctxtp -> num_send_msgs;
  1553. status = NdisAllocateMemoryWithTag (& ctxtp -> frame_dscrp, size,
  1554. UNIV_POOL_TAG);
  1555. if (status != NDIS_STATUS_SUCCESS)
  1556. {
  1557. UNIV_PRINT (("error allocating frame descriptors %d %x", size, status));
  1558. LOG_MSG2 (MSG_ERROR_MEMORY, MSG_NONE, size, status);
  1559. goto error;
  1560. }
  1561. size = ctxtp -> num_send_msgs;
  1562. NdisAllocatePacketPool (& status, & ctxtp -> frame_pool_handle,
  1563. ctxtp -> num_send_msgs,
  1564. sizeof (MAIN_PROTOCOL_RESERVED));
  1565. if (status != NDIS_STATUS_SUCCESS)
  1566. {
  1567. UNIV_PRINT (("error allocating ping packet pool %d %x", size, status));
  1568. LOG_MSG2 (MSG_ERROR_MEMORY, MSG_NONE, size, status);
  1569. goto error;
  1570. }
  1571. size = 5 * ctxtp -> num_send_msgs;
  1572. NdisAllocateBufferPool (& status, & ctxtp -> frame_buf_pool_handle,
  1573. 5 * ctxtp -> num_send_msgs);
  1574. if (status != NDIS_STATUS_SUCCESS)
  1575. {
  1576. UNIV_PRINT (("error allocating ping buffer pool %d %x", size, status));
  1577. LOG_MSG2 (MSG_ERROR_MEMORY, MSG_NONE, size, status);
  1578. goto error;
  1579. }
  1580. for (i = 0; i < ctxtp -> num_send_msgs; i ++)
  1581. {
  1582. dscrp = & (ctxtp -> frame_dscrp [i]);
  1583. if (ctxtp -> medium == NdisMedium802_3)
  1584. {
  1585. /* this buffer describes Ethernet MAC header */
  1586. size = sizeof (CVY_ETHERNET_HDR);
  1587. NdisAllocateBuffer (& status, & dscrp -> media_hdr_bufp,
  1588. ctxtp -> frame_buf_pool_handle,
  1589. & dscrp -> media_hdr . ethernet,
  1590. sizeof (CVY_ETHERNET_HDR));
  1591. if (status != NDIS_STATUS_SUCCESS)
  1592. {
  1593. UNIV_PRINT (("error allocating ethernet header buffer %d %x", i, status));
  1594. LOG_MSG3 (MSG_ERROR_MEMORY, MSG_NONE, i, size, status);
  1595. goto error;
  1596. }
  1597. dscrp -> recv_len = 0;
  1598. }
  1599. dscrp -> recv_len += sizeof (MAIN_FRAME_HDR) + sizeof (PING_MSG);
  1600. /* this buffer describes frame headers */
  1601. size = sizeof (MAIN_FRAME_HDR);
  1602. NdisAllocateBuffer (& status, & dscrp -> frame_hdr_bufp,
  1603. ctxtp -> frame_buf_pool_handle,
  1604. & dscrp -> frame_hdr,
  1605. sizeof (MAIN_FRAME_HDR));
  1606. if (status != NDIS_STATUS_SUCCESS)
  1607. {
  1608. UNIV_PRINT (("error allocating frame header buffer %d %x", i, status));
  1609. LOG_MSG3 (MSG_ERROR_MEMORY, MSG_NONE, i, size, status);
  1610. return FALSE;
  1611. }
  1612. /* this buffer describes receive ping message buffer V1.1.4 */
  1613. size = sizeof (PING_MSG);
  1614. NdisAllocateBuffer (& status, & dscrp -> recv_data_bufp,
  1615. ctxtp -> frame_buf_pool_handle,
  1616. & dscrp -> msg,
  1617. sizeof (PING_MSG));
  1618. if (status != NDIS_STATUS_SUCCESS)
  1619. {
  1620. UNIV_PRINT (("error allocating recv msg buffer %d %x", i, status));
  1621. LOG_MSG3 (MSG_ERROR_MEMORY, MSG_NONE, i, size, status);
  1622. return FALSE;
  1623. }
  1624. /* this buffer describes send ping message buffer V1.1.4 */
  1625. #if 0
  1626. size = sizeof (PING_MSG);
  1627. NdisAllocateBuffer (& status, & dscrp -> send_data_bufp,
  1628. ctxtp -> frame_buf_pool_handle,
  1629. ctxtp -> load_msgp,
  1630. sizeof (PING_MSG));
  1631. if (status != NDIS_STATUS_SUCCESS)
  1632. {
  1633. UNIV_PRINT (("error allocating send msg buffer %d %x", i, status));
  1634. LOG_MSG3 (MSG_ERROR_MEMORY, MSG_NONE, i, size, status);
  1635. return FALSE;
  1636. }
  1637. #endif
  1638. dscrp -> send_data_bufp = NULL; /* Allocate this in Main_frame_get */
  1639. NdisInterlockedInsertTailList (& ctxtp -> frame_list,
  1640. & dscrp -> link,
  1641. & ctxtp -> frame_lock);
  1642. }
  1643. /* Initialize the bi-directional affinity teaming if it has been configured. */
  1644. if (!Main_teaming_init(ctxtp))
  1645. {
  1646. ctxtp -> convoy_enabled = FALSE;
  1647. ctxtp -> params_valid = FALSE;
  1648. UNIV_PRINT (("error initializing bi-directional affinity teaming"));
  1649. }
  1650. UNIV_PRINT (("Initialized bi-directional affinity teaming"));
  1651. return NDIS_STATUS_SUCCESS;
  1652. error:
  1653. Main_cleanup (ctxtp);
  1654. return NDIS_STATUS_FAILURE;
  1655. } /* end Main_init */
  1656. VOID Main_cleanup (
  1657. PMAIN_CTXT ctxtp)
  1658. {
  1659. ULONG i, j;
  1660. PMAIN_BUFFER bp;
  1661. /* V1.1.4 */
  1662. /* #ps# */
  1663. /* While using packet stacking, ensure that all packets are returned
  1664. * before clearing up the context
  1665. */
  1666. #if 0 // no longer needed, since Ndis will take care of this for us
  1667. while (1)
  1668. {
  1669. NDIS_STATUS status;
  1670. ULONG count;
  1671. status = NdisQueryPendingIOCount (ctxtp -> mac_handle, & count);
  1672. if (status != NDIS_STATUS_SUCCESS || count == 0)
  1673. break;
  1674. Nic_sleep (10);
  1675. }
  1676. #endif
  1677. NdisDeleteNPagedLookasideList (& ctxtp -> resp_list);
  1678. for (i = 0; i < CVY_MAX_ALLOCS; i ++)
  1679. {
  1680. if (ctxtp -> send_pool_handle [i] != NULL)
  1681. {
  1682. while (1)
  1683. {
  1684. if (NdisPacketPoolUsage (ctxtp -> send_pool_handle [i]) == 0)
  1685. break;
  1686. Nic_sleep (10); /* wait for 10 milliseconds for the packets to be returned */
  1687. }
  1688. NdisFreePacketPool (ctxtp -> send_pool_handle [i]);
  1689. ctxtp -> send_pool_handle [i] = NULL;
  1690. }
  1691. if (ctxtp -> recv_pool_handle [i] != NULL)
  1692. {
  1693. while (1)
  1694. {
  1695. if (NdisPacketPoolUsage (ctxtp -> recv_pool_handle [i]) == 0)
  1696. break;
  1697. Nic_sleep (10); /* wait for 10 milliseconds for the packets to be returned */
  1698. }
  1699. NdisFreePacketPool (ctxtp -> recv_pool_handle [i]);
  1700. ctxtp -> recv_pool_handle [i] = NULL;
  1701. }
  1702. if (ctxtp -> act_buf [i] != NULL)
  1703. NdisFreeMemory (ctxtp -> act_buf [i],
  1704. ctxtp -> num_actions * ctxtp -> act_size, 0);
  1705. /* V1.3.2b */
  1706. if (ctxtp -> buf_array [i] != NULL)
  1707. {
  1708. for (j = 0; j < ctxtp -> num_packets; j ++)
  1709. {
  1710. bp = (PMAIN_BUFFER) (ctxtp -> buf_array [i] + j * ctxtp -> buf_size);
  1711. if (bp -> full_bufp != NULL)
  1712. {
  1713. NdisAdjustBufferLength (bp -> full_bufp,
  1714. ctxtp -> buf_mac_hdr_len +
  1715. ctxtp -> max_frame_size);
  1716. NdisFreeBuffer (bp -> full_bufp);
  1717. }
  1718. if (bp -> frame_bufp != NULL)
  1719. {
  1720. NdisAdjustBufferLength (bp -> frame_bufp,
  1721. ctxtp -> max_frame_size);
  1722. NdisFreeBuffer (bp -> frame_bufp);
  1723. }
  1724. }
  1725. NdisFreeMemory (ctxtp -> buf_array [i],
  1726. ctxtp -> num_packets * ctxtp -> buf_size, 0);
  1727. }
  1728. if (ctxtp -> buf_pool_handle [i] != NULL)
  1729. NdisFreeBufferPool (ctxtp -> buf_pool_handle [i]);
  1730. }
  1731. if (ctxtp -> frame_dscrp != NULL)
  1732. {
  1733. for (i = 0; i < ctxtp -> num_send_msgs; i ++)
  1734. {
  1735. if (ctxtp -> frame_dscrp [i] . media_hdr_bufp != NULL)
  1736. NdisFreeBuffer (ctxtp -> frame_dscrp [i] . media_hdr_bufp);
  1737. if (ctxtp -> frame_dscrp [i] . frame_hdr_bufp != NULL)
  1738. NdisFreeBuffer (ctxtp -> frame_dscrp [i] . frame_hdr_bufp);
  1739. if (ctxtp -> frame_dscrp [i] . send_data_bufp != NULL)
  1740. NdisFreeBuffer (ctxtp -> frame_dscrp [i] . send_data_bufp);
  1741. if (ctxtp -> frame_dscrp [i] . recv_data_bufp != NULL)
  1742. NdisFreeBuffer (ctxtp -> frame_dscrp [i] . recv_data_bufp);
  1743. }
  1744. NdisFreeMemory (ctxtp -> frame_dscrp, sizeof (MAIN_FRAME_DSCR) *
  1745. ctxtp -> num_send_msgs, 0);
  1746. }
  1747. if (ctxtp -> frame_buf_pool_handle != NULL)
  1748. NdisFreeBufferPool (ctxtp -> frame_buf_pool_handle);
  1749. /* This packet pool is being used only for the heartbeat messages,
  1750. * so prefer not to check the packet pool usage.
  1751. */
  1752. if (ctxtp -> frame_pool_handle != NULL)
  1753. NdisFreePacketPool (ctxtp -> frame_pool_handle);
  1754. NdisFreeSpinLock (& ctxtp -> sync_lock);
  1755. NdisFreeSpinLock (& ctxtp -> act_lock);
  1756. NdisFreeSpinLock (& ctxtp -> buf_lock); /* V1.3.2b */
  1757. NdisFreeSpinLock (& ctxtp -> recv_lock);
  1758. NdisFreeSpinLock (& ctxtp -> send_lock);
  1759. NdisFreeSpinLock (& ctxtp -> frame_lock);
  1760. NdisFreeSpinLock (& ctxtp -> rct_lock);
  1761. /* Cleanup BDA teaming state. Note: this function will sleep under certain circumstances. */
  1762. Main_teaming_cleanup(ctxtp);
  1763. if (ctxtp -> convoy_enabled)
  1764. Load_stop (& ctxtp -> load);
  1765. Load_cleanup (& ctxtp -> load);
  1766. NdisFreeSpinLock (& ctxtp -> load_lock);
  1767. return;
  1768. } /* end Main_cleanup */
  1769. ULONG Main_arp_handle (
  1770. PMAIN_CTXT ctxtp,
  1771. PARP_HDR arp_hdrp,
  1772. ULONG len, /* v2.0.6 */
  1773. ULONG send)
  1774. {
  1775. PUCHAR macp;
  1776. /* V1.3.0b multicast support - ARP spoofing. use either this one or
  1777. code in Nic_request_complete that makes TCP/IP believe that station
  1778. current MAC address is the multicast one */
  1779. /* V1.3.1b */
  1780. if (len < sizeof(ARP_HDR)) /* v2.0.6 */
  1781. return FALSE;
  1782. #if defined(TRACE_ARP)
  1783. DbgPrint ("(ARP) %s\n", send ? "send" : "recv");
  1784. DbgPrint (" MAC type = %x\n", ARP_GET_MAC_TYPE (arp_hdrp));
  1785. DbgPrint (" prot type = %x\n", ARP_GET_PROT_TYPE (arp_hdrp));
  1786. DbgPrint (" MAC length = %d\n", ARP_GET_MAC_LEN (arp_hdrp));
  1787. DbgPrint (" prot length = %d\n", ARP_GET_PROT_LEN (arp_hdrp));
  1788. DbgPrint (" message type = %d\n", ARP_GET_MSG_TYPE (arp_hdrp));
  1789. DbgPrint (" src MAC addr = %02x-%02x-%02x-%02x-%02x-%02x\n",
  1790. ARP_GET_SRC_MAC (arp_hdrp, 0),
  1791. ARP_GET_SRC_MAC (arp_hdrp, 1),
  1792. ARP_GET_SRC_MAC (arp_hdrp, 2),
  1793. ARP_GET_SRC_MAC (arp_hdrp, 3),
  1794. ARP_GET_SRC_MAC (arp_hdrp, 4),
  1795. ARP_GET_SRC_MAC (arp_hdrp, 5));
  1796. DbgPrint (" src prot addr = %d.%d.%d.%d\n",
  1797. ARP_GET_SRC_PROT (arp_hdrp, 0),
  1798. ARP_GET_SRC_PROT (arp_hdrp, 1),
  1799. ARP_GET_SRC_PROT (arp_hdrp, 2),
  1800. ARP_GET_SRC_PROT (arp_hdrp, 3));
  1801. DbgPrint (" dst MAC addr = %02x-%02x-%02x-%02x-%02x-%02x\n",
  1802. ARP_GET_DST_MAC (arp_hdrp, 0),
  1803. ARP_GET_DST_MAC (arp_hdrp, 1),
  1804. ARP_GET_DST_MAC (arp_hdrp, 2),
  1805. ARP_GET_DST_MAC (arp_hdrp, 3),
  1806. ARP_GET_DST_MAC (arp_hdrp, 4),
  1807. ARP_GET_DST_MAC (arp_hdrp, 5));
  1808. DbgPrint (" dst prot addr = %d.%d.%d.%d\n",
  1809. ARP_GET_DST_PROT (arp_hdrp, 0),
  1810. ARP_GET_DST_PROT (arp_hdrp, 1),
  1811. ARP_GET_DST_PROT (arp_hdrp, 2),
  1812. ARP_GET_DST_PROT (arp_hdrp, 3));
  1813. #endif
  1814. /* block sending out ARPs while we are changing IPs */
  1815. if (send && univ_changing_ip > 0)
  1816. {
  1817. /* if source IP is the one we are switching to - stop blocking ARPs */
  1818. if (ARP_GET_SRC_PROT_64(arp_hdrp) == ctxtp->cl_ip_addr) /* 64-bit -- ramkrish */
  1819. {
  1820. NdisAcquireSpinLock (& ctxtp -> load_lock);
  1821. univ_changing_ip = 0;
  1822. NdisReleaseSpinLock (& ctxtp -> load_lock);
  1823. UNIV_PRINT (("IP address changed - stop blocking"));
  1824. }
  1825. else if (ARP_GET_SRC_PROT_64(arp_hdrp) != ctxtp -> ded_ip_addr) /* 64-bit -- ramkrish */
  1826. {
  1827. #if defined(TRACE_ARP)
  1828. DbgPrint ("blocked due to IP switching\n");
  1829. #endif
  1830. // ctxtp -> arps_filtered ++;
  1831. return FALSE;
  1832. }
  1833. }
  1834. if (ctxtp -> params . mcast_spoof &&
  1835. ctxtp -> params . mcast_support &&
  1836. ARP_GET_PROT_TYPE (arp_hdrp) == ARP_PROT_TYPE_IP &&
  1837. ARP_GET_PROT_LEN (arp_hdrp) == ARP_PROT_LEN_IP)
  1838. {
  1839. if (send)
  1840. {
  1841. /* if this is a cluster IP address and our dedicated MAC -
  1842. replace dedicated MAC with cluster MAC */
  1843. if (ARP_GET_SRC_PROT_64 (arp_hdrp) != ctxtp -> ded_ip_addr) /* 64-bit -- ramkrish */
  1844. {
  1845. macp = ARP_GET_SRC_MAC_PTR (arp_hdrp);
  1846. if (CVY_MAC_ADDR_COMP (ctxtp -> medium, macp, & ctxtp -> ded_mac_addr))
  1847. CVY_MAC_ADDR_COPY (ctxtp -> medium, macp, & ctxtp -> cl_mac_addr);
  1848. }
  1849. #if defined (NLB_MIXED_MODE_CLUSTERS)
  1850. return TRUE;
  1851. #endif /* NLB_MIXED_MODE_CLUSTERS */
  1852. }
  1853. #if 0
  1854. else
  1855. {
  1856. /* if this is a cluster IP address and our cluster MAC -
  1857. replace cluster MAC with dedicated MAC */
  1858. if (ARP_GET_SRC_PROT_64 (arp_hdrp) != ctxtp -> ded_ip_addr) /* 64-bit -- ramkrish */
  1859. {
  1860. macp = ARP_GET_SRC_MAC_PTR (arp_hdrp);
  1861. if (CVY_MAC_ADDR_COMP (ctxtp -> medium, macp, & ctxtp -> cl_mac_addr))
  1862. CVY_MAC_ADDR_COPY (ctxtp -> medium, macp, & ctxtp -> ded_mac_addr);
  1863. }
  1864. if (ARP_GET_DST_PROT_64 (arp_hdrp) != ctxtp -> ded_ip_addr) /* 64-bit -- ramkrish */
  1865. {
  1866. macp = ARP_GET_DST_MAC_PTR (arp_hdrp);
  1867. if (CVY_MAC_ADDR_COMP (ctxtp -> medium, macp, & ctxtp -> cl_mac_addr))
  1868. CVY_MAC_ADDR_COPY (ctxtp -> medium, macp, & ctxtp -> ded_mac_addr);
  1869. }
  1870. }
  1871. #endif
  1872. }
  1873. #if defined (NLB_MIXED_MODE_CLUSTERS)
  1874. // code for migrating between cluster modes
  1875. if (!send)
  1876. {
  1877. if (ARP_GET_SRC_PROT_64 (arp_hdrp) != ctxtp -> ded_ip_addr)
  1878. {
  1879. macp = ARP_GET_SRC_MAC_PTR (arp_hdrp);
  1880. if (CVY_MAC_ADDR_COMP (ctxtp -> medium, macp, & ctxtp -> cl_mac_addr))
  1881. {
  1882. if (ctxtp -> params . mcast_support) /* only change for multicast support */
  1883. {
  1884. CVY_MAC_ADDR_COPY (ctxtp -> medium, macp, & ctxtp -> ded_mac_addr);
  1885. }
  1886. }
  1887. else /* some machine could be in another mode. Avoid the IP address conflict, but warn the user */
  1888. {
  1889. if (CVY_MAC_ADDR_COMP (ctxtp -> medium, macp, & ctxtp -> unic_mac_addr) ||
  1890. CVY_MAC_ADDR_COMP (ctxtp -> medium, macp, & ctxtp -> mult_mac_addr) ||
  1891. CVY_MAC_ADDR_COMP (ctxtp -> medium, macp, & ctxtp -> igmp_mac_addr))
  1892. {
  1893. UNIV_PRINT (("Detected a host with a different mode"));
  1894. if (! ctxtp -> mac_addr_warned)
  1895. {
  1896. ctxtp -> mac_addr_warned = TRUE;
  1897. LOG_MSG(MSG_WARN_DIFFERENT_MODE, MSG_NONE);
  1898. }
  1899. if (ctxtp -> params . mcast_support)
  1900. CVY_MAC_ADDR_COPY (ctxtp -> medium, macp, & ctxtp -> ded_mac_addr);
  1901. else
  1902. CVY_MAC_ADDR_COPY (ctxtp -> medium, macp, & ctxtp -> cl_mac_addr);
  1903. }
  1904. else
  1905. {
  1906. ; /* This will be a genuine IP address conflict */
  1907. }
  1908. }
  1909. }
  1910. if (ARP_GET_DST_PROT_64 (arp_hdrp) != ctxtp -> ded_ip_addr)
  1911. {
  1912. macp = ARP_GET_DST_MAC_PTR (arp_hdrp);
  1913. if (CVY_MAC_ADDR_COMP (ctxtp -> medium, macp, & ctxtp -> cl_mac_addr))
  1914. {
  1915. if (ctxtp -> params . mcast_support) /* only change for multicast support */
  1916. {
  1917. CVY_MAC_ADDR_COPY (ctxtp -> medium, macp, & ctxtp -> ded_mac_addr);
  1918. }
  1919. }
  1920. else /* some machine could be in another mode. Avoid the IP address conflict, but warn the user */
  1921. {
  1922. if (CVY_MAC_ADDR_COMP (ctxtp -> medium, macp, & ctxtp -> unic_mac_addr) ||
  1923. CVY_MAC_ADDR_COMP (ctxtp -> medium, macp, & ctxtp -> mult_mac_addr) ||
  1924. CVY_MAC_ADDR_COMP (ctxtp -> medium, macp, & ctxtp -> igmp_mac_addr))
  1925. {
  1926. UNIV_PRINT (("Detected a host with a different mode"));
  1927. if (! ctxtp -> mac_addr_warned)
  1928. {
  1929. ctxtp -> mac_addr_warned = TRUE;
  1930. LOG_MSG(MSG_WARN_DIFFERENT_MODE, MSG_NONE);
  1931. }
  1932. if (ctxtp -> params . mcast_support)
  1933. CVY_MAC_ADDR_COPY (ctxtp -> medium, macp, & ctxtp -> ded_mac_addr);
  1934. else
  1935. CVY_MAC_ADDR_COPY (ctxtp -> medium, macp, & ctxtp -> cl_mac_addr);
  1936. }
  1937. else
  1938. {
  1939. ; /* This will be a genuine IP address conflict */
  1940. }
  1941. }
  1942. }
  1943. }
  1944. #endif /* NLB_MIXED_MODE_CLUSTERS */
  1945. #if defined(TRACE_ARP)
  1946. DbgPrint ("---- spoofed to -----\n");
  1947. DbgPrint (" src MAC addr = %02x-%02x-%02x-%02x-%02x-%02x\n",
  1948. ARP_GET_SRC_MAC (arp_hdrp, 0),
  1949. ARP_GET_SRC_MAC (arp_hdrp, 1),
  1950. ARP_GET_SRC_MAC (arp_hdrp, 2),
  1951. ARP_GET_SRC_MAC (arp_hdrp, 3),
  1952. ARP_GET_SRC_MAC (arp_hdrp, 4),
  1953. ARP_GET_SRC_MAC (arp_hdrp, 5));
  1954. DbgPrint (" src prot addr = %d.%d.%d.%d\n",
  1955. ARP_GET_SRC_PROT (arp_hdrp, 0),
  1956. ARP_GET_SRC_PROT (arp_hdrp, 1),
  1957. ARP_GET_SRC_PROT (arp_hdrp, 2),
  1958. ARP_GET_SRC_PROT (arp_hdrp, 3));
  1959. DbgPrint (" dst MAC addr = %02x-%02x-%02x-%02x-%02x-%02x\n",
  1960. ARP_GET_DST_MAC (arp_hdrp, 0),
  1961. ARP_GET_DST_MAC (arp_hdrp, 1),
  1962. ARP_GET_DST_MAC (arp_hdrp, 2),
  1963. ARP_GET_DST_MAC (arp_hdrp, 3),
  1964. ARP_GET_DST_MAC (arp_hdrp, 4),
  1965. ARP_GET_DST_MAC (arp_hdrp, 5));
  1966. DbgPrint (" dst prot addr = %d.%d.%d.%d\n",
  1967. ARP_GET_DST_PROT (arp_hdrp, 0),
  1968. ARP_GET_DST_PROT (arp_hdrp, 1),
  1969. ARP_GET_DST_PROT (arp_hdrp, 2),
  1970. ARP_GET_DST_PROT (arp_hdrp, 3));
  1971. #endif
  1972. return TRUE;
  1973. } /* end Main_arp_handle */
  1974. #if defined (NLB_SESSION_SUPPORT)
  1975. /*
  1976. * Function: Main_parse_ipsec
  1977. * Description: This function parses UDP packets received on port 500, which are IPSec
  1978. * control packets. This function attempts to recognize the start of an
  1979. * IPSec session - its virtual 'SYN' packet. IPSec sessions begin with an
  1980. * IKE key exchange which is an IKE Main Mode Security Association. This
  1981. * function parses the IKE header and payload to identify the Main Mode
  1982. * SAs, which NLB will treat like TCP SYNs - all other UDP 500 and IPSec
  1983. * traffic is treated like TCP data packets. The problem is that NLB
  1984. * cannot necessarily tell the difference between a new Main Mode SA and
  1985. * a re-key of an existing Main Mode SA. Therefore, if the client does not
  1986. * support intitial contact notification, then every Main Mode SA will be
  1987. * considered a new session, which means that sessions can potentially
  1988. * break depending on how often Main Mode SAs are negotiated. However, if
  1989. * the client does support initial contact notification, then the only Main
  1990. * Mode SAs that will be reported as such are the initial ones (when no state
  1991. * currently exists between the client and the server), which allows NLB to
  1992. * distinguish the two types of Main Mode SAs, which should allow NLB to
  1993. * reliably keep IPSec sessions "sticky". Note that there is no TCP FIN
  1994. * equivalent, so the descriptor for these sessions will be around forever,
  1995. * or until the load module is reset, or a new initial Main Mode SA arrives
  1996. * with the same address tuple, at which time the descriptor is removed and
  1997. * the correct host accepts the session and creates a new descriptor. IPSec
  1998. * can however, if desired, notify NLB through the connection notification
  1999. * APIs, telling NLB that the session has gone down, allowing NLB to clean
  2000. * out the descriptor for the session. This is not necessarily critical,
  2001. * but would be useful in the case where a host with stale information
  2002. * rejoins the cluster, which could cause two hosts to pass up packets for
  2003. * the same session - IPSec will toss them out, unless its a Main Mode SA.
  2004. * Its also useful in the case where IPSec has refused a connection, in
  2005. * which case there is no reason for NLB to keep the descriptors around.
  2006. * Parameters: pIKEPacket - a pointer to the IKE packet buffer (this is beyond the UDP header).
  2007. * cUDPDataLenght - the length of the corresponding buffer.
  2008. * Returns: BOOLEAN - TRUE if the packet is a new IPSec session, FALSE if it is not.
  2009. * Author: Created by shouse, 4.28.01
  2010. */
  2011. BOOLEAN Main_parse_ipsec (PUCHAR pIKEPacket, ULONG cUDPDataLength) {
  2012. /* Pointer to the IKE header. */
  2013. PIPSEC_ISAKMP_HDR pISAKMPHeader = (PIPSEC_ISAKMP_HDR)pIKEPacket;
  2014. /* Pointer to the subsequent generic payloads in the IKE packet. */
  2015. PIPSEC_GENERIC_HDR pGenericHeader;
  2016. /* The responder cookie - should be zero for a new MM SA. */
  2017. UCHAR MainModeRCookie[IPSEC_ISAKMP_HEADER_RCOOKIE_LENGTH] = IPSEC_ISAKMP_MAIN_MODE_RCOOKIE;
  2018. /* The initiator cookie - should be non-zero if this is really an IKE packet. */
  2019. UCHAR EncapsulatedIPSecICookie[IPSEC_ISAKMP_HEADER_ICOOKIE_LENGTH] = IPSEC_ISAKMP_ENCAPSULATED_IPSEC_ICOOKIE;
  2020. /* The Microsoft client vendor ID - used to determine whether or not the client supports initial contact notification. */
  2021. UCHAR VIDMicrosoftClient[IPSEC_VENDOR_HEADER_VENDOR_ID_LENGTH] = IPSEC_VENDOR_ID_MICROSOFT;
  2022. /* Whether or not we've determined the client to be compatible. */
  2023. BOOLEAN bInitialContactEnabled = FALSE;
  2024. /* Whether or not this is indeed an initial contact. */
  2025. BOOLEAN bInitialContact = FALSE;
  2026. /* The length of the IKE packet. */
  2027. ULONG cISAKMPPacketLength;
  2028. /* The next payload code in the IKE payload chain. */
  2029. UCHAR NextPayload;
  2030. UNIV_PRINT(("Sniffing IKE header %p\n", pISAKMPHeader));
  2031. /* The UDP data should be at least as long as the initiator cookie. If the packet is
  2032. UDP encapsulated IPSec, then the I cookie will be 0 to indicate such. */
  2033. if (cUDPDataLength < IPSEC_ISAKMP_HEADER_ICOOKIE_LENGTH) {
  2034. UNIV_PRINT(("Malformed UDP data: UDP data length = %u\n", cUDPDataLength));
  2035. return FALSE;
  2036. }
  2037. /* Need to check the init cookie, which will distinguish clients behind a NAT,
  2038. which also send their IPSec (ESP) traffic to UDP port 500. If the I cookie
  2039. is zero, then this is NOT an IKE packet, so we return FALSE. */
  2040. if (NdisEqualMemory((PVOID)IPSEC_ISAKMP_GET_ICOOKIE_POINTER(pISAKMPHeader), (PVOID)&EncapsulatedIPSecICookie[0], sizeof(UCHAR) * IPSEC_ISAKMP_HEADER_ICOOKIE_LENGTH)) {
  2041. UNIV_PRINT(("This packet is UDP encapsulated IPSec traffic, not an IKE packet\n"));
  2042. return FALSE;
  2043. }
  2044. /* At this point, this packet should be IKE, so the UDP data should be at least
  2045. as long as an ISAKMP header. */
  2046. if (cUDPDataLength < IPSEC_ISAKMP_HEADER_LENGTH) {
  2047. UNIV_PRINT(("Malformed ISAKMP header: UDP data length = %u\n", cUDPDataLength));
  2048. return FALSE;
  2049. }
  2050. /* Get the total length of the IKE packet from the ISAKMP header. */
  2051. cISAKMPPacketLength = IPSEC_ISAKMP_GET_PACKET_LENGTH(pISAKMPHeader);
  2052. /* The IKE packet should be at least as long as an ISAKMP header (a whole lot longer, actually). */
  2053. if (cISAKMPPacketLength < IPSEC_ISAKMP_HEADER_LENGTH) {
  2054. UNIV_PRINT(("Malformed ISAKMP header: ISAKMP Packet length = %u\n", cISAKMPPacketLength));
  2055. return FALSE;
  2056. }
  2057. /* Sanity check - the UDP data length and IKE packet length SHOULD be the same. */
  2058. if (cUDPDataLength != cISAKMPPacketLength) {
  2059. UNIV_PRINT(("Expected equal packet lenghts: UDP data length = %u, ISAKMP packet length = %u\n", cUDPDataLength, cISAKMPPacketLength));
  2060. return FALSE;
  2061. }
  2062. /* Get the first payload type out of the ISAKMP header. */
  2063. NextPayload = IPSEC_ISAKMP_GET_NEXT_PAYLOAD(pISAKMPHeader);
  2064. /* IKE security associations are identified by a payload type byte in the header.
  2065. Check that first - this does not ensure that this is what we are looking for
  2066. because this check will not exclude, for instance, main mode re-keys. */
  2067. if (NextPayload != IPSEC_ISAKMP_SA) {
  2068. UNIV_PRINT(("Not a Main Mode Security Association\n"));
  2069. return FALSE;
  2070. }
  2071. /* Now check the resp cookie. If the cookie is all zeros, this is a new main mode
  2072. SA. However, we are only really interested in initial contact main mode SAs
  2073. (the first SA for a particular client), so we need to look a bit further. */
  2074. if (!NdisEqualMemory((PVOID)IPSEC_ISAKMP_GET_RCOOKIE_POINTER(pISAKMPHeader), (PVOID)&MainModeRCookie[0], sizeof(UCHAR) * IPSEC_ISAKMP_HEADER_RCOOKIE_LENGTH)) {
  2075. UNIV_PRINT(("Not a new Main Mode Security Association\n"));
  2076. return FALSE;
  2077. }
  2078. /* Calculate a pointer to the fist generic payload, which is directly after the ISAKMP header. */
  2079. pGenericHeader = (PIPSEC_GENERIC_HDR)((PUCHAR)pISAKMPHeader + IPSEC_ISAKMP_HEADER_LENGTH);
  2080. /* We are looping through the generic payloads looking for the vendor ID and/or notify information. */
  2081. while ((PUCHAR)pGenericHeader <= ((PUCHAR)pISAKMPHeader + cISAKMPPacketLength - IPSEC_GENERIC_HEADER_LENGTH)) {
  2082. /* Extract the payload length from the generic header. */
  2083. USHORT cPayloadLength = IPSEC_GENERIC_GET_PAYLOAD_LENGTH(pGenericHeader);
  2084. /* Not all clients are going to support this (in fact, only the Microsoft client
  2085. will support it, so we need to first see what the vendor ID of the client is.
  2086. if it is a Microsoft client that supports the initial contact vendor ID, then
  2087. we'll look for the initial contact, which provides better stickiness for IPSec
  2088. connections. If either the client is non-MS, or if it is not a version that
  2089. supports initial contact, then we can revert to the "second-best" solution,
  2090. which is to provide stickiness _between_ Main Mode SAs. This means that if a
  2091. client re-keys their Main Mode session, they _may_ be rebalanced to another
  2092. server. This is still better than the old UDP implementation, but the only
  2093. way to provide full session support for IPSec (without the distributed session
  2094. table nightmare) is to be able to distinguish initial Main Mode SAs from sub-
  2095. sequent Main Mode SAs (re-keys). */
  2096. if (NextPayload == IPSEC_ISAKMP_VENDOR_ID) {
  2097. PIPSEC_VENDOR_HDR pVendorHeader = (PIPSEC_VENDOR_HDR)pGenericHeader;
  2098. /* Make sure that the vendor ID payload is at least as long as a vendor ID. */
  2099. if (cPayloadLength < (IPSEC_GENERIC_HEADER_LENGTH + IPSEC_VENDOR_HEADER_VENDOR_ID_LENGTH)) {
  2100. UNIV_PRINT(("Malformed vendor ID header: Payload length = %d\n", cPayloadLength));
  2101. break;
  2102. }
  2103. /* Look for the Microsoft client vendor ID. If it is the right version, then we know that
  2104. the client is going to appropriately set the initial contact information, allowing NLB
  2105. to provide the best possible support for session stickiness. */
  2106. if (NdisEqualMemory((PVOID)IPSEC_VENDOR_ID_GET_ID_POINTER(pVendorHeader), (PVOID)&VIDMicrosoftClient[0], sizeof(UCHAR) * IPSEC_VENDOR_HEADER_VENDOR_ID_LENGTH)) {
  2107. /* Make sure that their is a version number attached to the Microsoft Vendor ID. Not
  2108. all vendor IDs have versions attached, but the Microsoft vendor ID should. */
  2109. if (cPayloadLength < (IPSEC_GENERIC_HEADER_LENGTH + IPSEC_VENDOR_ID_PAYLOAD_LENGTH)) {
  2110. UNIV_PRINT(("Unable to determine MS client version: Payload length = %d\n", cPayloadLength));
  2111. break;
  2112. }
  2113. if (IPSEC_VENDOR_ID_GET_VERSION(pVendorHeader) >= IPSEC_VENDOR_ID_MICROSOFT_MIN_VERSION) {
  2114. /* Microsoft clients whose version is greater than or equal to 4 will support
  2115. initial contact. Non-MS clients, or old MS clients will not, so they
  2116. receive decent, but not guaranteed sitckines, based solely on MM SAs. */
  2117. bInitialContactEnabled = TRUE;
  2118. }
  2119. }
  2120. } else if (NextPayload == IPSEC_ISAKMP_NOTIFY) {
  2121. PIPSEC_NOTIFY_HDR pNotifyHeader = (PIPSEC_NOTIFY_HDR)pGenericHeader;
  2122. /* Make sure that the notify payload is the correct length. */
  2123. if (cPayloadLength < (IPSEC_GENERIC_HEADER_LENGTH + IPSEC_NOTIFY_PAYLOAD_LENGTH)) {
  2124. UNIV_PRINT(("Malformed notify header: Payload length = %d\n", cPayloadLength));
  2125. break;
  2126. }
  2127. if (IPSEC_NOTIFY_GET_NOTIFY_MESSAGE(pNotifyHeader) == IPSEC_NOTIFY_INITIAL_CONTACT) {
  2128. /* This is an initial contact notification from the client, which means that this is
  2129. the first time that the client has contacted this server; more precisely, the client
  2130. currently has no state associated with this peer. NLB will "re-balance" on initial
  2131. contact notifications, but not other Main Mode key exchanges as long as it can
  2132. determine that the client will comply with initial contact notification. */
  2133. bInitialContact = TRUE;
  2134. }
  2135. }
  2136. /* Get the next payload type out of the generic header. */
  2137. NextPayload = IPSEC_GENERIC_GET_NEXT_PAYLOAD(pGenericHeader);
  2138. /* Calculate a pointer to the next generic payload. */
  2139. pGenericHeader = (PIPSEC_GENERIC_HDR)((PUCHAR)pGenericHeader + cPayloadLength);
  2140. }
  2141. /* If the vendor ID did not indicate that this client supports initial contact notification,
  2142. then return TRUE, and we go with the less-than-optimal solution of treating Main Mode
  2143. SAs as the connection boundaries, which potentially breaks sessions on MM SA re-keys. */
  2144. if (!bInitialContactEnabled) {
  2145. UNIV_PRINT(("This client does not support initial contact notifications.\n"));
  2146. return TRUE;
  2147. }
  2148. /* If this was a Main Mode SA from a client that supports initial contact, but did not
  2149. specify the initial contact vendor ID, then this is a re-key for an existing session. */
  2150. if (!bInitialContact) {
  2151. UNIV_PRINT(("Not an initial contact Main Mode Security Association\n"));
  2152. return FALSE;
  2153. }
  2154. /* Otherwise, this IS a Main Mode SA initial contact, which the IPSec 'SYN'. */
  2155. UNIV_PRINT(("Found an initial contact Main Mode Security Association\n"));
  2156. return TRUE;
  2157. }
  2158. #else /* !NLB_SESSION_SUPPORT */
  2159. BOOLEAN Main_parse_ipsec (PUCHAR pIKEPacket, ULONG cUDPDataLength) {
  2160. return FALSE;
  2161. }
  2162. #endif /* NLB_SESSION_SUPPORT */
  2163. //+----------------------------------------------------------------------------
  2164. //
  2165. // Function: Main_ip_send_filter
  2166. //
  2167. // Description: Filter outgoing IP packets
  2168. //
  2169. // Arguments: MAIN_CTXT ctxtp -
  2170. // const PIP_HDR ip_hdrp -
  2171. // const PUCHAR hdrp -
  2172. // ULONG len -
  2173. // IN OUT PULONG pOperation -
  2174. // IN: has to be MAIN_FILTER_OP_NONE
  2175. // OUT: MAIN_FILTER_OP_NONE or MAIN_FILTER_OP_CTRL
  2176. //
  2177. // Returns: BOOLEAN - TRUE if to allow the packet to go through
  2178. // FALSE if to drop the packet
  2179. //
  2180. // History: kyrilf initial code
  2181. // fengsun Created seperate function 11/14/00
  2182. //
  2183. //+----------------------------------------------------------------------------
  2184. BOOLEAN Main_ip_send_filter (
  2185. PMAIN_CTXT ctxtp,
  2186. const PIP_HDR ip_hdrp,
  2187. const PUCHAR hdrp,
  2188. ULONG len,
  2189. IN OUT PULONG pOperation)
  2190. {
  2191. PUDP_HDR udp_hdrp = NULL;
  2192. PTCP_HDR tcp_hdrp = NULL;
  2193. BOOLEAN acpt = TRUE; // Whether or not to accept the packet.
  2194. ULONG svr_port; // Port for this host.
  2195. ULONG svr_addr; // IP address for this host.
  2196. ULONG clt_port; // Port for destination client.
  2197. ULONG clt_addr; // IP address for destination client.
  2198. ULONG flags; // TCP flags.
  2199. ULONG hlen;
  2200. ULONG Protocol; // Protocol derived from IP header.
  2201. BOOLEAN bRefused = FALSE; // TRUE -> BDA has refused handling this packet.
  2202. hlen = sizeof (ULONG) * IP_GET_HLEN (ip_hdrp);
  2203. if (len < hlen)
  2204. return FALSE;
  2205. #if defined(TRACE_IP)
  2206. DbgPrint ("(IP) send \n");
  2207. DbgPrint (" version = %d\n", IP_GET_VERS (ip_hdrp));
  2208. DbgPrint (" header length = %d\n", IP_GET_HLEN (ip_hdrp));
  2209. DbgPrint (" service type = 0x%x\n", IP_GET_SRVC (ip_hdrp));
  2210. DbgPrint (" packet length = %d\n", IP_GET_PLEN (ip_hdrp));
  2211. DbgPrint (" frag ident = %d\n", IP_GET_FRAG_ID (ip_hdrp));
  2212. DbgPrint (" frag flags = 0x%x\n", IP_GET_FRAG_FLGS (ip_hdrp));
  2213. DbgPrint (" frag offset = %d\n", IP_GET_FRAG_OFF (ip_hdrp));
  2214. DbgPrint (" time to live = %d\n", IP_GET_TTL (ip_hdrp));
  2215. DbgPrint (" checksum = 0x04%x\n", IP_GET_CHKSUM (ip_hdrp));
  2216. DbgPrint (" protocol = %d ", IP_GET_PROT (ip_hdrp));
  2217. #endif
  2218. UNIV_ASSERT(*pOperation == MAIN_FILTER_OP_NONE);
  2219. if (IP_GET_FRAG_OFF(ip_hdrp) != 0)
  2220. {
  2221. #if defined(TRACE_FRAGS)
  2222. if ((IP_GET_FRAG_FLGS(ip_hdrp) & 0x1) == 0)
  2223. DbgPrint("Fragmented datagram id %d flgs %x off %d received from %d.%d.%d.%d\n",
  2224. IP_GET_FRAG_ID(ip_hdrp),
  2225. IP_GET_FRAG_FLGS(ip_hdrp),
  2226. IP_GET_FRAG_OFF(ip_hdrp),
  2227. IP_GET_SRC_ADDR (ip_hdrp, 0),
  2228. IP_GET_SRC_ADDR (ip_hdrp, 1),
  2229. IP_GET_SRC_ADDR (ip_hdrp, 2),
  2230. IP_GET_SRC_ADDR (ip_hdrp, 3));
  2231. #endif
  2232. /* Always let fragmented packets go out. */
  2233. return TRUE;
  2234. }
  2235. /* Server address is the source IP and client address is the destination IP. */
  2236. svr_addr = IP_GET_SRC_ADDR_64 (ip_hdrp);
  2237. clt_addr = IP_GET_DST_ADDR_64 (ip_hdrp);
  2238. /* Get the IP protocol form the IP header. */
  2239. Protocol = IP_GET_PROT(ip_hdrp);
  2240. /* Packets directed to the dedicated IP address are always passed through. If the
  2241. cluster IP address hasn't been set (parameter error), then fall into a pass-
  2242. through mode and pass all traffic up to the upper-layer protocols. */
  2243. if (svr_addr == ctxtp -> ded_ip_addr || ctxtp -> cl_ip_addr == 0)
  2244. {
  2245. if (Protocol != TCPIP_PROTOCOL_UDP)
  2246. {
  2247. /* For UDP protocol, remote control packet has to be handled seperately, so don't accept it yet. */
  2248. return TRUE;
  2249. }
  2250. }
  2251. switch (IP_GET_PROT (ip_hdrp))
  2252. {
  2253. case TCPIP_PROTOCOL_TCP:
  2254. #if defined(TRACE_IP) || defined(TRACE_TCP)
  2255. DbgPrint ("(TCP) send \n");
  2256. #endif
  2257. tcp_hdrp = (PTCP_HDR) hdrp;
  2258. hlen += sizeof (ULONG) * TCP_GET_HLEN (tcp_hdrp); /* v2.0.6 */
  2259. if (len < hlen)
  2260. return FALSE;
  2261. #if defined(TRACE_TCP)
  2262. DbgPrint (" source port = %d\n", TCP_GET_SRC_PORT (tcp_hdrp));
  2263. DbgPrint (" dest port = %d\n", TCP_GET_DST_PORT (tcp_hdrp));
  2264. DbgPrint (" seq no. = %d\n", TCP_GET_SEQ_NO (tcp_hdrp));
  2265. DbgPrint (" ack no. = %d\n", TCP_GET_ACK_NO (tcp_hdrp));
  2266. DbgPrint (" flags = %d\n", TCP_GET_FLAGS (tcp_hdrp));
  2267. #endif
  2268. svr_port = TCP_GET_SRC_PORT (tcp_hdrp);
  2269. clt_port = TCP_GET_DST_PORT (tcp_hdrp);
  2270. /* For PPTP support, because we cannot extract a source port number from the subsequent GRE packets
  2271. in order to match them to an existing PPTP TCP descriptor, we will hardcode the source port number
  2272. here and then do the same for GRE packets. This way, we can treat GRE packets like TCP data packets
  2273. on this TCP connection. Note that this breaks when clients are behind a NAT because a single client
  2274. IP address will have many connections to port 1723, each with a different source port. In that case,
  2275. we break because we are not reference counting SYNs v. FINs - i.e., the first PPTP connection to go
  2276. down would destroy the TCP descriptor for (Client IP, 0, Server IP, 1723). There are two solutions;
  2277. (1) reference count re-used descriptors (so we require 2 FINs per SYN, not just 2 period), or (2)
  2278. have PPTP use our notification APIs to give us something that we can look for in the GRE packets,
  2279. such as a call ID, to identify the GRE packet as belonging to a known session. */
  2280. if (svr_port == PPTP_CTRL_PORT)
  2281. {
  2282. if (ctxtp -> convoy_enabled)
  2283. {
  2284. if (NLB_PPTP_SESSION_SUPPORT_ENABLED()) // JosephJ: added 0 && because I'm disabling PPTP session support for now...
  2285. {
  2286. clt_port = 0;
  2287. }
  2288. else
  2289. {
  2290. acpt = Main_packet_check(ctxtp, svr_addr, svr_port, clt_addr, clt_port, TCPIP_PROTOCOL_UDP, &bRefused, FALSE);
  2291. /* If teaming has suggested that we not allow this packet to pass, dump it. */
  2292. if (bRefused) acpt = FALSE;
  2293. break;
  2294. }
  2295. }
  2296. else
  2297. {
  2298. acpt = FALSE;
  2299. break;
  2300. }
  2301. }
  2302. UNIV_ASSERT(IP_GET_FRAG_OFF(ip_hdrp) == 0);
  2303. /* Apply filtering algorithm. process connection boundaries different from regular packets. */
  2304. /* Get the TCP flags to find out the packet type. */
  2305. flags = TCP_GET_FLAGS (tcp_hdrp);
  2306. if (flags & TCP_FLAG_SYN)
  2307. {
  2308. #if defined(TRACE_CNCT)
  2309. DbgPrint ("outgoing SYN %x from %d.%d.%d.%d:%d\n",
  2310. TCP_GET_FLAGS (tcp_hdrp),
  2311. IP_GET_SRC_ADDR (ip_hdrp, 0),
  2312. IP_GET_SRC_ADDR (ip_hdrp, 1),
  2313. IP_GET_SRC_ADDR (ip_hdrp, 2),
  2314. IP_GET_SRC_ADDR (ip_hdrp, 3),
  2315. TCP_GET_SRC_PORT (tcp_hdrp));
  2316. #endif
  2317. /* In the case of an outgoing SYN, we always want to allow the packet to pass,
  2318. unless the operation was refused (in the case on an inactive BDA team), so
  2319. we ignore the return value, which is the response from the load module, and
  2320. check only refused to determine whether or not to drop the packet. If this
  2321. adapter is part of a BDA team, this function will create a descriptor for
  2322. this TCP connection on the way out to make sure that it will come back to
  2323. this host, even if a convergence and bucket redistribution occurs before the
  2324. SYNACK is returned from the destination. */
  2325. if (ctxtp -> convoy_enabled)
  2326. {
  2327. Main_create_dscr(ctxtp, svr_addr, svr_port, clt_addr, clt_port, TCPIP_PROTOCOL_TCP, &bRefused, TRUE);
  2328. /* If teaming has suggested that we not allow this packet to pass, dump it. */
  2329. if (bRefused) acpt = FALSE;
  2330. }
  2331. }
  2332. else if (flags & TCP_FLAG_FIN)
  2333. {
  2334. #if defined(TRACE_CNCT)
  2335. DbgPrint ("outgoing FIN %x from %d.%d.%d.%d:%d\n",
  2336. TCP_GET_FLAGS (tcp_hdrp),
  2337. IP_GET_SRC_ADDR (ip_hdrp, 0),
  2338. IP_GET_SRC_ADDR (ip_hdrp, 1),
  2339. IP_GET_SRC_ADDR (ip_hdrp, 2),
  2340. IP_GET_SRC_ADDR (ip_hdrp, 3),
  2341. TCP_GET_SRC_PORT (tcp_hdrp));
  2342. #endif
  2343. /* In the case of an outgoing FIN, we always want to allow the packet to pass,
  2344. unless the operation was refused (in the case on an inactive BDA team), so
  2345. we ignore the return value, which is the response from the load module, and
  2346. check only refused to determine whether or not to drop the packet. */
  2347. Main_conn_advise(ctxtp, svr_addr, svr_port, clt_addr, clt_port, TCPIP_PROTOCOL_TCP, CVY_CONN_DOWN, &bRefused, FALSE);
  2348. /* If teaming has suggested that we not allow this packet to pass, dump it. */
  2349. if (bRefused) acpt = FALSE;
  2350. }
  2351. else if (flags & TCP_FLAG_RST)
  2352. {
  2353. #if defined(TRACE_CNCT)
  2354. DbgPrint ("outgoing RST %x from %d.%d.%d.%d:%d\n",
  2355. TCP_GET_FLAGS (tcp_hdrp),
  2356. IP_GET_SRC_ADDR (ip_hdrp, 0),
  2357. IP_GET_SRC_ADDR (ip_hdrp, 1),
  2358. IP_GET_SRC_ADDR (ip_hdrp, 2),
  2359. IP_GET_SRC_ADDR (ip_hdrp, 3),
  2360. TCP_GET_SRC_PORT (tcp_hdrp));
  2361. #endif
  2362. /* In the case of an outgoing RST, we always want to allow the packet to pass,
  2363. unless the operation was refused (in the case on an inactive BDA team), so
  2364. we ignore the return value, which is the response from the load module, and
  2365. check only refused to determine whether or not to drop the packet. */
  2366. Main_conn_advise(ctxtp, svr_addr, svr_port, clt_addr, clt_port, TCPIP_PROTOCOL_TCP, CVY_CONN_RESET, &bRefused, FALSE);
  2367. /* If teaming has suggested that we not allow this packet to pass, dump it. */
  2368. if (bRefused) acpt = FALSE;
  2369. }
  2370. break;
  2371. case TCPIP_PROTOCOL_UDP:
  2372. #if defined(TRACE_IP) || defined(TRACE_UDP)
  2373. DbgPrint ("(UDP) send\n");
  2374. #endif
  2375. udp_hdrp = (PUDP_HDR) hdrp;
  2376. hlen += sizeof (UDP_HDR);
  2377. if (len < hlen)
  2378. return FALSE;
  2379. #if defined(TRACE_UDP)
  2380. DbgPrint (" source port = %d\n", UDP_GET_SRC_PORT (udp_hdrp));
  2381. DbgPrint (" dest port = %d\n", UDP_GET_DST_PORT (udp_hdrp));
  2382. DbgPrint (" length = %d\n", UDP_GET_LEN (udp_hdrp));
  2383. #endif
  2384. svr_port = UDP_GET_SRC_PORT (udp_hdrp);
  2385. clt_port = UDP_GET_DST_PORT (udp_hdrp);
  2386. /* IP broadcast UDPs generated by wlbs.exe. Note that we cannot look past UDP header on send and thus check the code. */
  2387. if ((clt_port == ctxtp -> params . rct_port || clt_port == CVY_DEF_RCT_PORT_OLD) && clt_addr == TCPIP_BCAST_ADDR) {
  2388. /* This flag is used by Main_send to enable loop back so that we can respond to a query originated on this host. */
  2389. *pOperation = MAIN_FILTER_OP_CTRL;
  2390. }
  2391. /* Always allow outgoing UDP packets to go through. */
  2392. UNIV_ASSERT(acpt == TRUE);
  2393. break;
  2394. case TCPIP_PROTOCOL_GRE:
  2395. #if defined(TRACE_IP) || defined(TRACE_GRE)
  2396. DbgPrint ("(GRE) send\n");
  2397. #endif
  2398. if (ctxtp -> convoy_enabled)
  2399. {
  2400. if (!NLB_PPTP_SESSION_SUPPORT_ENABLED())
  2401. {
  2402. acpt = Main_packet_check(ctxtp, svr_addr, PPTP_CTRL_PORT, clt_addr, 0, TCPIP_PROTOCOL_UDP, &bRefused, FALSE);
  2403. /* If teaming has suggested that we not allow this packet to pass, dump it. */
  2404. if (bRefused) acpt = FALSE;
  2405. }
  2406. /* Otherwise, PPTP packets are treated like TCP data, which are always allowed to pass. */
  2407. }
  2408. else
  2409. {
  2410. acpt = FALSE;
  2411. }
  2412. #if defined(TRACE_IP) || defined(TRACE_GRE)
  2413. DbgPrint ("accepted %d\n", acpt);
  2414. #endif
  2415. break;
  2416. case TCPIP_PROTOCOL_IPSEC1:
  2417. case TCPIP_PROTOCOL_IPSEC2:
  2418. #if defined(TRACE_IP) || defined(TRACE_IPSEC)
  2419. DbgPrint ("(IPSEC %d) send \n", IP_GET_PROT (ip_hdrp));
  2420. #endif
  2421. if (ctxtp -> convoy_enabled)
  2422. {
  2423. if (!NLB_IPSEC_SESSION_SUPPORT_ENABLED())
  2424. {
  2425. acpt = Main_packet_check(ctxtp, svr_addr, IPSEC_CTRL_PORT, clt_addr, 0, TCPIP_PROTOCOL_UDP, &bRefused, FALSE);
  2426. /* If teaming has suggested that we not allow this packet to pass, dump it. */
  2427. if (bRefused) acpt = FALSE;
  2428. }
  2429. /* Otherwise, IPSec packets are treated kind of like TCP data, which are always allowed to pass. */
  2430. }
  2431. else
  2432. {
  2433. acpt = FALSE;
  2434. }
  2435. #if defined(TRACE_IP) || defined(TRACE_IPSEC)
  2436. DbgPrint ("accepted %d\n", acpt);
  2437. #endif
  2438. break;
  2439. case TCPIP_PROTOCOL_ICMP:
  2440. #if defined(TRACE_IP)
  2441. DbgPrint ("(ICMP)\n");
  2442. #endif
  2443. /* Allow all outgoing ICMP to pass; incoming ICMP may be filtered, however. */
  2444. break;
  2445. default:
  2446. /* Allow other protocols to go out on all hosts. */
  2447. #if defined(TRACE_IP)
  2448. DbgPrint ("(unknown)\n");
  2449. #endif
  2450. break;
  2451. }
  2452. #if defined(TRACE_IP) || defined(TRACE_TCP) || defined(TRACE_UDP)
  2453. DbgPrint (" src address = %d.%d.%d.%d\n",
  2454. IP_GET_SRC_ADDR (ip_hdrp, 0),
  2455. IP_GET_SRC_ADDR (ip_hdrp, 1),
  2456. IP_GET_SRC_ADDR (ip_hdrp, 2),
  2457. IP_GET_SRC_ADDR (ip_hdrp, 3));
  2458. DbgPrint (" dst address = %d.%d.%d.%d\n",
  2459. IP_GET_DST_ADDR (ip_hdrp, 0),
  2460. IP_GET_DST_ADDR (ip_hdrp, 1),
  2461. IP_GET_DST_ADDR (ip_hdrp, 2),
  2462. IP_GET_DST_ADDR (ip_hdrp, 3));
  2463. DbgPrint ("\n");
  2464. #endif
  2465. return acpt;
  2466. }
  2467. //+----------------------------------------------------------------------------
  2468. //
  2469. // Function: Main_ip_recv_filter
  2470. //
  2471. // Description: Filter incoming IP packets
  2472. //
  2473. // Arguments: MAIN_CTXT ctxtp -
  2474. // const PIP_HDR ip_hdrp -
  2475. // const PUCHAR hdrp -
  2476. // ULONG len -
  2477. // IN OUT PULONG pOperation -
  2478. // IN: has to be MAIN_FILTER_OP_NONE
  2479. // OUT: MAIN_FILTER_OP_NONE
  2480. // MAIN_FILTER_OP_CTRL
  2481. // MAIN_FILTER_OP_NBT
  2482. //
  2483. // Returns: BOOLEAN - TRUE if to allow the packet to go through
  2484. // FALSE if to drop the packet
  2485. //
  2486. // History: kyrilf initial code
  2487. // fengsun Created seperate function 11/14/00
  2488. //
  2489. //+----------------------------------------------------------------------------
  2490. BOOLEAN Main_ip_recv_filter(
  2491. PMAIN_CTXT ctxtp,
  2492. const PIP_HDR ip_hdrp,
  2493. const PUCHAR hdrp,
  2494. ULONG len,
  2495. IN OUT PULONG pOperation)
  2496. {
  2497. PUDP_HDR udp_hdrp = NULL;
  2498. PTCP_HDR tcp_hdrp = NULL;
  2499. BOOLEAN acpt = TRUE; // Whether or not to accept the packet.
  2500. ULONG svr_port; // Port for this host.
  2501. ULONG svr_addr; // IP address for this host.
  2502. ULONG clt_port; // Port for destination client.
  2503. ULONG clt_addr; // IP address for destination client.
  2504. ULONG flags; // TCP flags.
  2505. ULONG hlen;
  2506. BOOLEAN fragmented = FALSE;
  2507. ULONG Protocol; // Protocol derived from IP header.
  2508. BOOLEAN bRefused = FALSE; // TRUE -> BDA has refused handling this packet.
  2509. hlen = sizeof (ULONG) * IP_GET_HLEN (ip_hdrp);
  2510. if (len < hlen)
  2511. return FALSE;
  2512. #if defined(TRACE_IP)
  2513. DbgPrint ("(IP) recv\n");
  2514. DbgPrint (" version = %d\n", IP_GET_VERS (ip_hdrp));
  2515. DbgPrint (" header length = %d\n", IP_GET_HLEN (ip_hdrp));
  2516. DbgPrint (" service type = 0x%x\n", IP_GET_SRVC (ip_hdrp));
  2517. DbgPrint (" packet length = %d\n", IP_GET_PLEN (ip_hdrp));
  2518. DbgPrint (" frag ident = %d\n", IP_GET_FRAG_ID (ip_hdrp));
  2519. DbgPrint (" frag flags = 0x%x\n", IP_GET_FRAG_FLGS (ip_hdrp));
  2520. DbgPrint (" frag offset = %d\n", IP_GET_FRAG_OFF (ip_hdrp));
  2521. DbgPrint (" time to live = %d\n", IP_GET_TTL (ip_hdrp));
  2522. DbgPrint (" checksum = 0x04%x\n", IP_GET_CHKSUM (ip_hdrp));
  2523. DbgPrint (" protocol = %d ", IP_GET_PROT (ip_hdrp));
  2524. #endif
  2525. UNIV_ASSERT(*pOperation == MAIN_FILTER_OP_NONE);
  2526. /* Server address is the destination IP and client address is the source IP. */
  2527. svr_addr = IP_GET_DST_ADDR_64(ip_hdrp);
  2528. clt_addr = IP_GET_SRC_ADDR_64(ip_hdrp);
  2529. /* Get the protocol ID from the IP header. */
  2530. Protocol = IP_GET_PROT(ip_hdrp);
  2531. /* Packets directed to the dedicated IP address are always passed through. If the
  2532. cluster IP address hasn't been set (parameter error), then fall into a pass-
  2533. through mode and pass all traffic up to the upper-layer protocols. */
  2534. if (svr_addr == ctxtp -> ded_ip_addr || ctxtp -> cl_ip_addr == 0 ||
  2535. svr_addr == ctxtp -> ded_bcast_addr || svr_addr == ctxtp -> cl_bcast_addr)
  2536. {
  2537. if (Protocol != TCPIP_PROTOCOL_UDP)
  2538. {
  2539. /* For UDP protocol, remote control packet has to be handled seperately, so don't accept it yet. */
  2540. return TRUE;
  2541. }
  2542. }
  2543. /* If the load module is stopped, drop most packets. */
  2544. if (! ctxtp -> convoy_enabled)
  2545. {
  2546. /* Drop TCP, GRE and IPSEC immediately. Non-remote-control UDP will also
  2547. be dropped, but other protocols will be allowed to pass. */
  2548. if (Protocol == TCPIP_PROTOCOL_TCP || Protocol == TCPIP_PROTOCOL_GRE ||
  2549. Protocol == TCPIP_PROTOCOL_IPSEC1 || Protocol == TCPIP_PROTOCOL_IPSEC2)
  2550. {
  2551. /* For UDP protocol, remote control packet has to be handled seperately, so don't accept it yet. */
  2552. return FALSE;
  2553. }
  2554. }
  2555. #if defined(TRACE_FRAGS)
  2556. if ((IP_GET_FRAG_FLGS(ip_hdrp) & 0x1) != 0)
  2557. {
  2558. DbgPrint("Fragmented datagram id %d flgs %x off %d received from %d.%d.%d.%d\n",
  2559. IP_GET_FRAG_ID(ip_hdrp),
  2560. IP_GET_FRAG_FLGS(ip_hdrp),
  2561. IP_GET_FRAG_OFF(ip_hdrp),
  2562. IP_GET_SRC_ADDR (ip_hdrp, 0),
  2563. IP_GET_SRC_ADDR (ip_hdrp, 1),
  2564. IP_GET_SRC_ADDR (ip_hdrp, 2),
  2565. IP_GET_SRC_ADDR (ip_hdrp, 3));
  2566. }
  2567. #endif
  2568. if (IP_GET_FRAG_OFF(ip_hdrp) != 0)
  2569. {
  2570. #if defined(TRACE_FRAGS)
  2571. if ((IP_GET_FRAG_FLGS(ip_hdrp) & 0x1) == 0)
  2572. DbgPrint("Fragmented datagram id %d flgs %x off %d received from %d.%d.%d.%d\n",
  2573. IP_GET_FRAG_ID(ip_hdrp),
  2574. IP_GET_FRAG_FLGS(ip_hdrp),
  2575. IP_GET_FRAG_OFF(ip_hdrp),
  2576. IP_GET_SRC_ADDR (ip_hdrp, 0),
  2577. IP_GET_SRC_ADDR (ip_hdrp, 1),
  2578. IP_GET_SRC_ADDR (ip_hdrp, 2),
  2579. IP_GET_SRC_ADDR (ip_hdrp, 3));
  2580. #endif
  2581. /* In optimized-fragment mode; If we have no rules, or a single rule that will
  2582. not look at anything or only source IP address (the only exception to this
  2583. is multiple handling mode with no affinity that also uses source port for
  2584. its decision making), then we can just rely on normal mechanism to handle
  2585. every fragmented packet, since the algorithm will not attempt to look past
  2586. the IP header.
  2587. For multiple rules, or single rule with no affinity, apply algorithm only
  2588. to the first packet that has UDP/TCP header and then let fragmented packets
  2589. up on all of the systems. TCP will then do the right thing and throw away
  2590. the fragments on all of the systems other than the one that handled the first
  2591. fragment.
  2592. If port rules will not let us handle IP fragments reliably, let TCP filter
  2593. them out based on sequence numbers. */
  2594. if (! ctxtp -> optimized_frags)
  2595. return TRUE;
  2596. fragmented = TRUE;
  2597. }
  2598. switch (Protocol)
  2599. {
  2600. case TCPIP_PROTOCOL_TCP:
  2601. #if defined(TRACE_IP) || defined(TRACE_TCP)
  2602. DbgPrint ("(TCP) recv\n");
  2603. #endif
  2604. tcp_hdrp = (PTCP_HDR) hdrp;
  2605. if (! fragmented)
  2606. {
  2607. hlen += sizeof (ULONG) * TCP_GET_HLEN (tcp_hdrp);
  2608. if (len < hlen)
  2609. return FALSE;
  2610. #if defined(TRACE_TCP)
  2611. DbgPrint (" source port = %d\n", TCP_GET_SRC_PORT (tcp_hdrp));
  2612. DbgPrint (" dest port = %d\n", TCP_GET_DST_PORT (tcp_hdrp));
  2613. DbgPrint (" seq no. = %d\n", TCP_GET_SEQ_NO (tcp_hdrp));
  2614. DbgPrint (" ack no. = %d\n", TCP_GET_ACK_NO (tcp_hdrp));
  2615. DbgPrint (" flags = %d\n", TCP_GET_FLAGS (tcp_hdrp));
  2616. #endif
  2617. clt_port = TCP_GET_SRC_PORT (tcp_hdrp);
  2618. svr_port = TCP_GET_DST_PORT (tcp_hdrp);
  2619. /* For PPTP support, because we cannot extract a source port number from the subsequent GRE packets
  2620. in order to match them to an existing PPTP TCP descriptor, we will hardcode the source port number
  2621. here and then do the same for GRE packets. This way, we can treat GRE packets like TCP data packets
  2622. on this TCP connection. Note that this breaks when clients are behind a NAT because a single client
  2623. IP address will have many connections to port 1723, each with a different source port. In that case,
  2624. we break because we are not reference counting SYNs v. FINs - i.e., the first PPTP connection to go
  2625. down would destroy the TCP descriptor for (Client IP, 0, Server IP, 1723). There are two solutions;
  2626. (1) reference count re-used descriptors (so we require 2 FINs per SYN, not just 2 period), or (2)
  2627. have PPTP use our notification APIs to give us something that we can look for in the GRE packets,
  2628. such as a call ID, to identify the GRE packet as belonging to a known session. */
  2629. if (svr_port == PPTP_CTRL_PORT)
  2630. {
  2631. if (NLB_PPTP_SESSION_SUPPORT_ENABLED())
  2632. {
  2633. clt_port = 0;
  2634. }
  2635. else
  2636. {
  2637. UNIV_ASSERT(ctxtp -> convoy_enabled);
  2638. acpt = Main_packet_check(ctxtp, svr_addr, svr_port, clt_addr, clt_port, TCPIP_PROTOCOL_UDP, &bRefused, FALSE);
  2639. /* If teaming has suggested that we not allow this packet to pass, dump it. */
  2640. if (bRefused) acpt = FALSE;
  2641. break;
  2642. }
  2643. }
  2644. flags = TCP_GET_FLAGS (tcp_hdrp);
  2645. }
  2646. else
  2647. {
  2648. clt_port = 0;
  2649. svr_port = 0;
  2650. flags = 0;
  2651. }
  2652. /* Apply filtering algorithm. Process connection boundaries different from regular packets. */
  2653. if (flags & TCP_FLAG_SYN)
  2654. {
  2655. #if defined(TRACE_CNCT)
  2656. DbgPrint ("incoming SYN %x from %d.%d.%d.%d:%d\n",
  2657. TCP_GET_FLAGS (tcp_hdrp),
  2658. IP_GET_SRC_ADDR (ip_hdrp, 0),
  2659. IP_GET_SRC_ADDR (ip_hdrp, 1),
  2660. IP_GET_SRC_ADDR (ip_hdrp, 2),
  2661. IP_GET_SRC_ADDR (ip_hdrp, 3),
  2662. TCP_GET_SRC_PORT (tcp_hdrp));
  2663. #endif
  2664. acpt = Main_conn_advise(ctxtp, svr_addr, svr_port, clt_addr, clt_port, TCPIP_PROTOCOL_TCP, CVY_CONN_UP, &bRefused, FALSE);
  2665. /* If teaming has suggested that we not allow this packet to pass, dump it. */
  2666. if (bRefused) acpt = FALSE;
  2667. }
  2668. else if (flags & TCP_FLAG_FIN)
  2669. {
  2670. #if defined(TRACE_CNCT)
  2671. DbgPrint ("incoming FIN %x from %d.%d.%d.%d:%d\n",
  2672. TCP_GET_FLAGS (tcp_hdrp),
  2673. IP_GET_SRC_ADDR (ip_hdrp, 0),
  2674. IP_GET_SRC_ADDR (ip_hdrp, 1),
  2675. IP_GET_SRC_ADDR (ip_hdrp, 2),
  2676. IP_GET_SRC_ADDR (ip_hdrp, 3),
  2677. TCP_GET_SRC_PORT (tcp_hdrp));
  2678. #endif
  2679. acpt = Main_conn_advise(ctxtp, svr_addr, svr_port, clt_addr, clt_port, TCPIP_PROTOCOL_TCP, CVY_CONN_DOWN, &bRefused, FALSE);
  2680. /* If teaming has suggested that we not allow this packet to pass, dump it. */
  2681. if (bRefused) acpt = FALSE;
  2682. }
  2683. else if (flags & TCP_FLAG_RST)
  2684. {
  2685. #if defined(TRACE_CNCT)
  2686. DbgPrint ("incoming RST %x from %d.%d.%d.%d:%d\n",
  2687. TCP_GET_FLAGS (tcp_hdrp),
  2688. IP_GET_SRC_ADDR (ip_hdrp, 0),
  2689. IP_GET_SRC_ADDR (ip_hdrp, 1),
  2690. IP_GET_SRC_ADDR (ip_hdrp, 2),
  2691. IP_GET_SRC_ADDR (ip_hdrp, 3),
  2692. TCP_GET_SRC_PORT (tcp_hdrp));
  2693. #endif
  2694. acpt = Main_conn_advise(ctxtp, svr_addr, svr_port, clt_addr, clt_port, TCPIP_PROTOCOL_TCP, CVY_CONN_RESET, &bRefused, FALSE);
  2695. /* If teaming has suggested that we not allow this packet to pass, dump it. */
  2696. if (bRefused) acpt = FALSE;
  2697. }
  2698. else
  2699. {
  2700. UNIV_ASSERT(! (flags & (TCP_FLAG_SYN | TCP_FLAG_FIN | TCP_FLAG_RST)));
  2701. acpt = Main_packet_check(ctxtp, svr_addr, svr_port, clt_addr, clt_port, TCPIP_PROTOCOL_TCP, &bRefused, FALSE);
  2702. /* If teaming has suggested that we not allow this packet to pass, dump it. */
  2703. if (bRefused) acpt = FALSE;
  2704. /* Post-process NBT traffic on receive. */
  2705. if (svr_port == NBT_SESSION_PORT && ctxtp -> params . nbt_support && acpt)
  2706. * pOperation = MAIN_FILTER_OP_NBT;
  2707. }
  2708. break;
  2709. case TCPIP_PROTOCOL_UDP:
  2710. #if defined(TRACE_IP) || defined(TRACE_UDP)
  2711. DbgPrint ("(UDP) recv \n");
  2712. #endif
  2713. udp_hdrp = (PUDP_HDR) hdrp;
  2714. hlen += sizeof (UDP_HDR);
  2715. if (! fragmented)
  2716. {
  2717. if (len < hlen)
  2718. return FALSE;
  2719. #if defined(TRACE_UDP)
  2720. DbgPrint (" source port = %d\n", UDP_GET_SRC_PORT (udp_hdrp));
  2721. DbgPrint (" dest port = %d\n", UDP_GET_DST_PORT (udp_hdrp));
  2722. DbgPrint (" length = %d\n", UDP_GET_LEN (udp_hdrp));
  2723. #endif
  2724. }
  2725. if (! fragmented)
  2726. {
  2727. clt_port = UDP_GET_SRC_PORT (udp_hdrp);
  2728. svr_port = UDP_GET_DST_PORT (udp_hdrp);
  2729. }
  2730. else
  2731. {
  2732. clt_port = 0;
  2733. svr_port = 0;
  2734. }
  2735. if (! fragmented)
  2736. {
  2737. if (clt_port == ctxtp -> params . rct_port || clt_port == CVY_DEF_RCT_PORT_OLD)
  2738. {
  2739. /* Allow incoming remote control response to go through on all hosts. */
  2740. PIOCTL_REMOTE_HDR rct_hdrp = (PIOCTL_REMOTE_HDR) UDP_GET_DGRAM_PTR(udp_hdrp);
  2741. if (rct_hdrp -> code == IOCTL_REMOTE_CODE) break;
  2742. }
  2743. /* Let remote control request go through regardless whether remote control is
  2744. enabled. Remote query could be processed even if remote control is disabled.
  2745. The request will be queued up and handled on receive complete. */
  2746. if (svr_port == ctxtp -> params . rct_port || svr_port == CVY_DEF_RCT_PORT_OLD)
  2747. {
  2748. PIOCTL_REMOTE_HDR rct_hdrp = (PIOCTL_REMOTE_HDR) UDP_GET_DGRAM_PTR(udp_hdrp);
  2749. /* Make sure this is our remote message. note that we are assuming that RCT
  2750. header imediatelly folows the UDP header. This is only TRUE on receive. */
  2751. if (rct_hdrp -> code == IOCTL_REMOTE_CODE)
  2752. {
  2753. /* Consume receives and handle them during the receive complete event. */
  2754. #if defined(TRACE_RCT)
  2755. DbgPrint ("(RCT) received on port %d from %d.%d.%d.%d:%d\n",
  2756. svr_port,
  2757. IP_GET_SRC_ADDR (ip_hdrp, 0),
  2758. IP_GET_SRC_ADDR (ip_hdrp, 1),
  2759. IP_GET_SRC_ADDR (ip_hdrp, 2),
  2760. IP_GET_SRC_ADDR (ip_hdrp, 3),
  2761. clt_port);
  2762. #endif
  2763. *pOperation = MAIN_FILTER_OP_CTRL;
  2764. break;
  2765. }
  2766. }
  2767. }
  2768. /* Packets directed to the dedicated IP address are always passed through. If the
  2769. cluster IP address hasn't been set (parameter error), then fall into a pass-
  2770. through mode and pass all traffic up to the upper-layer protocols. */
  2771. if (svr_addr == ctxtp -> ded_ip_addr || ctxtp -> cl_ip_addr == 0 ||
  2772. svr_addr == ctxtp -> ded_bcast_addr || svr_addr == ctxtp -> cl_bcast_addr)
  2773. break;
  2774. /* Apply filtering algorithm. */
  2775. if (ctxtp -> convoy_enabled)
  2776. {
  2777. /* UDP packets that arrive on port 500 are IPSec control packets. */
  2778. if (NLB_IPSEC_SESSION_SUPPORT_ENABLED() && svr_port == IPSEC_CTRL_PORT)
  2779. {
  2780. /* First, parse the IKE payload to find out whether or not
  2781. this is an initial contact IKE Main Mode SA. */
  2782. BOOLEAN bIsIKEInitialContact = Main_parse_ipsec((PUCHAR)udp_hdrp + sizeof(UDP_HDR), len - hlen);
  2783. /* If this is an intial contact, treat this as a TCP SYN. Otherwise, treat it like a TCP data packet. */
  2784. if (bIsIKEInitialContact) {
  2785. /* Because there may not be an explicit connection down notififcation from IPSec, we first need to clean out any
  2786. descriptor that might already exist for this tuple. If we still own the bucket, we'll just end up re-creating
  2787. it, but if we do not, then somebody else will, so we have to clean out the descriptor to keep us from handling
  2788. another host's traffic. Since this is just as likely to fail as succeed, and we don't really care either way,
  2789. ignore the return value. */
  2790. Main_conn_advise(ctxtp, svr_addr, svr_port, clt_addr, clt_port, TCPIP_PROTOCOL_IPSEC1, CVY_CONN_RESET, &bRefused, FALSE);
  2791. /* If we own the bucket for this tuple, we'll create a descriptor and accept the packet. If the client is not behind a
  2792. NAT, then the source port will be IPSEC_CTRL_PORT (500). If the client is behind a NAT, the source port will be
  2793. arbitrary, but will persist for the entire IPSec session, so we can use it to distinguish clients behind a NAT. In
  2794. such a scenario, all IPSec data (non-control traffic) is encapsulated in UDP packets, so the packet check will be
  2795. performed in the else case of this branch. In a non-NAT case, the data is in IPSec1/2 protocol packets, which will
  2796. be handled analagously in another case of this protocol switch statement. */
  2797. acpt = Main_conn_advise(ctxtp, svr_addr, svr_port, clt_addr, clt_port, TCPIP_PROTOCOL_IPSEC1, CVY_CONN_UP, &bRefused, FALSE);
  2798. } else {
  2799. /* If this is part of an existing IPSec session, then we have to have a descriptor in order to accpet it. This will
  2800. keep all IPSec traffic during the key exchange sticky, plus the data exchange if the client is behind a NAT. */
  2801. acpt = Main_packet_check(ctxtp, svr_addr, svr_port, clt_addr, clt_port, TCPIP_PROTOCOL_IPSEC1, &bRefused, FALSE);
  2802. }
  2803. if (bRefused) acpt = FALSE;
  2804. } else {
  2805. acpt = Main_packet_check(ctxtp, svr_addr, svr_port, clt_addr, clt_port, TCPIP_PROTOCOL_UDP, &bRefused, FALSE);
  2806. /* If teaming has suggested that we not allow this packet to pass, dump it. */
  2807. if (bRefused) acpt = FALSE;
  2808. }
  2809. }
  2810. else
  2811. {
  2812. acpt = FALSE;
  2813. }
  2814. break;
  2815. case TCPIP_PROTOCOL_GRE:
  2816. #if defined(TRACE_IP) || defined(TRACE_GRE)
  2817. DbgPrint ("(GRE) recv");
  2818. #endif
  2819. if (NLB_PPTP_SESSION_SUPPORT_ENABLED())
  2820. {
  2821. /* For PPTP support, because we cannot extract a source port number from the subsequent GRE packets
  2822. in order to match them to an existing PPTP TCP descriptor, we will hardcode the source port number
  2823. here and then do the same for GRE packets. This way, we can treat GRE packets like TCP data packets
  2824. on this TCP connection. Note that this breaks when clients are behind a NAT because a single client
  2825. IP address will have many connections to port 1723, each with a different source port. In that case,
  2826. we break because we are not reference counting SYNs v. FINs - i.e., the first PPTP connection to go
  2827. down would destroy the TCP descriptor for (Client IP, 0, Server IP, 1723). There are two solutions;
  2828. (1) reference count re-used descriptors (so we require 2 FINs per SYN, not just 2 period), or (2)
  2829. have PPTP use our notification APIs to give us something that we can look for in the GRE packets,
  2830. such as a call ID, to identify the GRE packet as belonging to a known session. */
  2831. acpt = Main_packet_check(ctxtp, svr_addr, PPTP_CTRL_PORT, clt_addr, 0, TCPIP_PROTOCOL_TCP, &bRefused, FALSE);
  2832. }
  2833. else
  2834. {
  2835. acpt = Main_packet_check(ctxtp, svr_addr, PPTP_CTRL_PORT, clt_addr, 0, TCPIP_PROTOCOL_UDP, &bRefused, FALSE);
  2836. }
  2837. /* If teaming has suggested that we not allow this packet to pass, dump it. */
  2838. if (bRefused) acpt = FALSE;
  2839. #if defined(TRACE_IP) || defined(TRACE_GRE)
  2840. DbgPrint ("accepted %d\n", acpt);
  2841. #endif
  2842. break;
  2843. case TCPIP_PROTOCOL_IPSEC1:
  2844. case TCPIP_PROTOCOL_IPSEC2:
  2845. #if defined(TRACE_IP) || defined(TRACE_IPSEC)
  2846. DbgPrint ("(IPSEC %d) recv \n", IP_GET_PROT (ip_hdrp));
  2847. #endif
  2848. if (NLB_IPSEC_SESSION_SUPPORT_ENABLED())
  2849. {
  2850. /* NLB_SESSION_SUPPORT: If this is part of an existing IPSec session, then we have to have a descriptor in order to accpet it. Because
  2851. this can only happen in the case where the client is NOT behind a NAT, we can safely hardcode the client port
  2852. to IPSEC_CTRL_PORT (500). In NAT scenarios, the data traffic is UDP encapsulated, not IPSec protocol type
  2853. traffic, and is distinguished by source port. */
  2854. acpt = Main_packet_check(ctxtp, svr_addr, IPSEC_CTRL_PORT, clt_addr, IPSEC_CTRL_PORT, TCPIP_PROTOCOL_IPSEC1, &bRefused, FALSE);
  2855. }
  2856. else
  2857. {
  2858. acpt = Main_packet_check(ctxtp, svr_addr, IPSEC_CTRL_PORT, clt_addr, 0, TCPIP_PROTOCOL_UDP, &bRefused, FALSE);
  2859. }
  2860. /* If teaming has suggested that we not allow this packet to pass, dump it. */
  2861. if (bRefused) acpt = FALSE;
  2862. #if defined(TRACE_IP) || defined(TRACE_IPSEC)
  2863. DbgPrint ("accepted %d\n", acpt);
  2864. #endif
  2865. break;
  2866. case TCPIP_PROTOCOL_ICMP:
  2867. /* In BDA teaming mode, we don't want all hosts to send up ICMP traffic, just one, due
  2868. to multiplicitive effects in a clustered router configuration. Hardcode the ports,
  2869. since ICMP has no notion of port numbers. */
  2870. acpt = Main_packet_check(ctxtp, svr_addr, 0, clt_addr, 0, TCPIP_PROTOCOL_UDP, &bRefused, TRUE);
  2871. /* If teaming has suggested that we not allow this packet to pass, dump it. */
  2872. if (bRefused) acpt = FALSE;
  2873. break;
  2874. default:
  2875. //
  2876. // Allow other protocols to go through on all hosts
  2877. //
  2878. #if defined(TRACE_IP)
  2879. DbgPrint ("(unknown)\n");
  2880. #endif
  2881. break;
  2882. }
  2883. #if defined(TRACE_IP) || defined(TRACE_TCP) || defined(TRACE_UDP)
  2884. DbgPrint (" src address = %d.%d.%d.%d\n",
  2885. IP_GET_SRC_ADDR (ip_hdrp, 0),
  2886. IP_GET_SRC_ADDR (ip_hdrp, 1),
  2887. IP_GET_SRC_ADDR (ip_hdrp, 2),
  2888. IP_GET_SRC_ADDR (ip_hdrp, 3));
  2889. DbgPrint (" dst address = %d.%d.%d.%d\n",
  2890. IP_GET_DST_ADDR (ip_hdrp, 0),
  2891. IP_GET_DST_ADDR (ip_hdrp, 1),
  2892. IP_GET_DST_ADDR (ip_hdrp, 2),
  2893. IP_GET_DST_ADDR (ip_hdrp, 3));
  2894. DbgPrint ("\n");
  2895. #endif
  2896. return acpt;
  2897. }
  2898. ULONG Main_recv_ping (
  2899. PMAIN_CTXT ctxtp,
  2900. PMAIN_FRAME_HDR cvy_hdrp)
  2901. {
  2902. #if defined(TRACE_CVY)
  2903. DbgPrint ("(CVY %d)\n", cvy_hdrp -> host);
  2904. #endif
  2905. /* V1.3.2b - do not need to protect here since we are not making the
  2906. decision to call Load_ routines */
  2907. if (! ctxtp -> convoy_enabled)
  2908. return FALSE;
  2909. /* only accept messages from our cluster */
  2910. if (cvy_hdrp->cl_ip_addr == 0 ||
  2911. cvy_hdrp->cl_ip_addr != ctxtp -> cl_ip_addr)
  2912. return FALSE;
  2913. /* sanity check host id */
  2914. if (cvy_hdrp -> host == 0 || cvy_hdrp -> host > CVY_MAX_HOSTS)
  2915. {
  2916. UNIV_PRINT (("bad host id %d", cvy_hdrp -> host));
  2917. if (! ctxtp -> bad_host_warned)
  2918. {
  2919. LOG_MSG1 (MSG_ERROR_HOST_ID, MSG_NONE, cvy_hdrp -> host);
  2920. ctxtp -> bad_host_warned = TRUE;
  2921. }
  2922. return FALSE;
  2923. }
  2924. if ((cvy_hdrp -> host != ctxtp -> params . host_priority) &&
  2925. (cvy_hdrp -> ded_ip_addr == ctxtp -> ded_ip_addr) &&
  2926. (ctxtp -> ded_ip_addr != 0))
  2927. {
  2928. UNIV_PRINT (("duplicate dedicated IP address 0x%x", ctxtp -> ded_ip_addr));
  2929. if (! ctxtp -> dup_ded_ip_warned)
  2930. {
  2931. LOG_MSG (MSG_ERROR_DUP_DED_IP_ADDR, ctxtp -> params . ded_ip_addr);
  2932. ctxtp -> dup_ded_ip_warned = TRUE;
  2933. }
  2934. }
  2935. /* might want to take appropriate actions for a message from a host
  2936. running different version number of software */
  2937. if (cvy_hdrp -> version != CVY_VERSION_FULL)
  2938. {
  2939. ;
  2940. }
  2941. return TRUE;
  2942. } /* end Main_recv_ping */
  2943. PNDIS_PACKET Main_send (
  2944. PMAIN_CTXT ctxtp,
  2945. PNDIS_PACKET packetp,
  2946. PULONG exhausted)
  2947. {
  2948. PUCHAR hdrp, mac_hdrp;
  2949. ULONG plen;
  2950. USHORT sig;
  2951. PUCHAR tcp_hdrp;
  2952. PNDIS_PACKET newp;
  2953. ULONG op = MAIN_FILTER_OP_NONE;
  2954. USHORT group;
  2955. * exhausted = FALSE;
  2956. /* extract payload, IP and MAC pointers */
  2957. hdrp = Main_frame_parse (ctxtp, packetp, & mac_hdrp, 0, & tcp_hdrp, & plen,
  2958. & sig, & group, TRUE);
  2959. if (hdrp == NULL)
  2960. return NULL;
  2961. /* process IP frames */
  2962. if (sig == TCPIP_IP_SIG) /* v2.0.6 */
  2963. {
  2964. if (tcp_hdrp == NULL ||
  2965. ! Main_ip_send_filter (ctxtp, (PIP_HDR) hdrp, tcp_hdrp, plen, & op))
  2966. return NULL;
  2967. }
  2968. /* process ARP frames */
  2969. else if (sig == TCPIP_ARP_SIG)
  2970. {
  2971. // ctxtp -> arps_count ++;
  2972. if (! Main_arp_handle (ctxtp, (PARP_HDR) hdrp, plen, TRUE)) /* v2.0.6 */
  2973. return NULL;
  2974. }
  2975. /* if still sending out - get a new packet */
  2976. newp = Main_packet_get (ctxtp, packetp, TRUE, group, plen);
  2977. * exhausted = (newp == NULL);
  2978. /* in unicast mode, if this is a remote control packet, make sure it will
  2979. loopback to us. */
  2980. if (newp != NULL && op == MAIN_FILTER_OP_CTRL)
  2981. NdisClearPacketFlags(newp, NDIS_FLAGS_DONT_LOOPBACK);
  2982. return newp;
  2983. } /* end Main_send */
  2984. PNDIS_PACKET Main_recv (
  2985. PMAIN_CTXT ctxtp,
  2986. PNDIS_PACKET packetp)
  2987. {
  2988. PMAIN_FRAME_HDR cvy_hdrp;
  2989. PUCHAR hdrp, mac_hdrp;
  2990. ULONG len, dlen, plen;
  2991. USHORT sig = 0;
  2992. PUCHAR tcp_hdrp;
  2993. PNDIS_PACKET newp;
  2994. PMAIN_BUFFER bp;
  2995. PMAIN_PROTOCOL_RESERVED resp;
  2996. PNDIS_PACKET_OOB_DATA oobp;
  2997. ULONG size, xferred;
  2998. PLIST_ENTRY entryp;
  2999. ULONG op = MAIN_FILTER_OP_NONE;
  3000. PNBT_HDR nbt_hdrp;
  3001. USHORT group;
  3002. ULONG packet_lowmark;
  3003. /* extract payload, IP and MAC pointers */
  3004. hdrp = Main_frame_parse (ctxtp, packetp, & mac_hdrp, 0, & tcp_hdrp, & len,
  3005. & sig, & group, FALSE);
  3006. if (hdrp == NULL)
  3007. return NULL;
  3008. plen = len;
  3009. cvy_hdrp = (PMAIN_FRAME_HDR) hdrp;
  3010. /* process IP frames */
  3011. if (sig == TCPIP_IP_SIG) /* v2.0.6 */
  3012. {
  3013. if (tcp_hdrp == NULL ||
  3014. ! Main_ip_recv_filter (ctxtp, (PIP_HDR) hdrp, tcp_hdrp, plen, & op))
  3015. return NULL;
  3016. }
  3017. /* process ARP frames */
  3018. else if (sig == TCPIP_ARP_SIG)
  3019. {
  3020. if (! Main_arp_handle (ctxtp, (PARP_HDR) hdrp, plen, FALSE)) /* v2.0.6 */
  3021. return NULL;
  3022. }
  3023. /* process heartbeat frames */
  3024. else if ((sig == MAIN_FRAME_SIG || sig == MAIN_FRAME_SIG_OLD) &&
  3025. cvy_hdrp -> code == MAIN_FRAME_CODE)
  3026. {
  3027. /* make sure it looks acceptable */
  3028. if (len >= sizeof (MAIN_FRAME_HDR) && Main_recv_ping (ctxtp, cvy_hdrp))
  3029. {
  3030. #if defined (NLB_MIXED_MODE_CLUSTERS)
  3031. // code for migrating between cluster modes
  3032. /* reject the packet if the mac address is not ours to allow unicast and multicast clusters to exist */
  3033. {
  3034. ULONG doff = CVY_MAC_DST_OFF (ctxtp -> medium);
  3035. if (ctxtp -> params . mcast_support &&
  3036. (! CVY_MAC_ADDR_COMP (ctxtp -> medium, mac_hdrp + doff, & ctxtp -> ded_mac_addr)))
  3037. {
  3038. return NULL;
  3039. }
  3040. }
  3041. #endif /* NLB_MIXED_MODE_CLUSTERS */
  3042. /* V2.2 switch into backward compatibility mode if a convoy hearbeat
  3043. is detected */
  3044. if (sig == MAIN_FRAME_SIG_OLD && ! ctxtp -> etype_old)
  3045. {
  3046. if (ctxtp -> medium == NdisMedium802_3)
  3047. {
  3048. CVY_ETHERNET_ETYPE_SET (& ctxtp -> media_hdr . ethernet, MAIN_FRAME_SIG_OLD);
  3049. }
  3050. ctxtp -> etype_old = TRUE;
  3051. }
  3052. if (len >= (sizeof (MAIN_FRAME_HDR) + sizeof (PING_MSG)))
  3053. {
  3054. /* recompute pointer to the ping message */
  3055. Main_frame_parse (ctxtp, packetp, & mac_hdrp, sizeof (MAIN_FRAME_HDR),
  3056. & hdrp, & len, & sig, & group, FALSE);
  3057. /* have load deal with contents */
  3058. NdisAcquireSpinLock (& ctxtp -> load_lock);
  3059. if (ctxtp -> convoy_enabled && hdrp != NULL) /* V1.3.2b, V2.0.6 */
  3060. Load_msg_rcv (& ctxtp -> load, (PPING_MSG) hdrp);
  3061. NdisReleaseSpinLock (& ctxtp -> load_lock);
  3062. }
  3063. else
  3064. {
  3065. UNIV_PRINT (("PING message size mismatch %d vs %d", len, sizeof (MAIN_FRAME_HDR) + sizeof (PING_MSG)));
  3066. }
  3067. }
  3068. if (! ctxtp -> params . netmon_alive)
  3069. return NULL;
  3070. }
  3071. /* post-process NBT traffic */
  3072. if (op == MAIN_FILTER_OP_NBT)
  3073. {
  3074. dlen = TCP_GET_DGRAM_LEN ((PIP_HDR) hdrp, (PTCP_HDR) tcp_hdrp);
  3075. /* have to re-parse packet to find offset to NBT header */
  3076. hdrp = Main_frame_parse (ctxtp, packetp, & mac_hdrp, len - dlen,
  3077. (PUCHAR * ) & nbt_hdrp, & len, & sig, & group,
  3078. FALSE);
  3079. /* V2.1 let TCP module mask machine name if necessary */
  3080. if (hdrp != NULL && nbt_hdrp != NULL &&
  3081. plen >= (((PUCHAR) nbt_hdrp) - ((PUCHAR) hdrp) + dlen))
  3082. {
  3083. Tcpip_nbt_handle (& ctxtp -> tcpip, (PIP_HDR) hdrp, (PTCP_HDR) tcp_hdrp,
  3084. dlen, nbt_hdrp);
  3085. }
  3086. }
  3087. /* get a new packet */
  3088. if (op != MAIN_FILTER_OP_CTRL)
  3089. {
  3090. newp = Main_packet_get (ctxtp, packetp, FALSE, group, plen);
  3091. if (newp == NULL)
  3092. ctxtp -> cntr_recv_no_buf ++; /* V2.0.6 */
  3093. }
  3094. /* copy incoming remote control packet into our own, so we re-use it later
  3095. to send back reply */
  3096. else
  3097. {
  3098. /* V1.3.2b */
  3099. newp = Main_packet_alloc (ctxtp, FALSE, & packet_lowmark);
  3100. if (newp == NULL)
  3101. {
  3102. ctxtp -> cntr_recv_no_buf ++; /* V2.0.6 */
  3103. return NULL;
  3104. }
  3105. /* get a buffer */
  3106. while (1)
  3107. {
  3108. NdisAcquireSpinLock (& ctxtp -> buf_lock);
  3109. entryp = RemoveHeadList (& ctxtp -> buf_list);
  3110. if (entryp != & ctxtp -> buf_list)
  3111. {
  3112. ctxtp->num_bufs_out++;
  3113. NdisReleaseSpinLock (& ctxtp -> buf_lock);
  3114. break;
  3115. }
  3116. NdisReleaseSpinLock (& ctxtp -> buf_lock);
  3117. UNIV_PRINT (("OUT OF BUFFERS!!!"));
  3118. if (! Main_bufs_alloc (ctxtp))
  3119. {
  3120. NdisFreePacket (newp);
  3121. ctxtp -> cntr_recv_no_buf ++; /* V2.0.6 */
  3122. return NULL;
  3123. }
  3124. }
  3125. bp = CONTAINING_RECORD (entryp, MAIN_BUFFER, link);
  3126. UNIV_ASSERT (bp -> code == MAIN_BUFFER_CODE);
  3127. size = ctxtp -> buf_mac_hdr_len + len;
  3128. NdisAdjustBufferLength (bp -> full_bufp, size);
  3129. NdisChainBufferAtFront (newp, bp -> full_bufp);
  3130. /* copy actual data */
  3131. NdisCopyFromPacketToPacket (newp, 0, size, packetp, 0, & xferred);
  3132. /* copy OOB info */
  3133. oobp = NDIS_OOB_DATA_FROM_PACKET (newp);
  3134. oobp -> HeaderSize = ctxtp -> buf_mac_hdr_len;
  3135. oobp -> MediaSpecificInformation = NULL;
  3136. oobp -> SizeMediaSpecificInfo = 0;
  3137. oobp -> TimeSent = 0;
  3138. oobp -> TimeReceived = 0;
  3139. /* shouse - Because packets marked as CTRL never pass above NLB in the
  3140. network stack, we can always use the ProtocolReserved field. */
  3141. resp = MAIN_PROTOCOL_FIELD (newp);
  3142. if (packet_lowmark)
  3143. NDIS_SET_PACKET_STATUS (newp, NDIS_STATUS_RESOURCES);
  3144. /* set protocol reserved fields */
  3145. resp -> type = MAIN_PACKET_TYPE_CTRL;
  3146. resp -> miscp = bp;
  3147. resp -> data = 0;
  3148. /* V2.0.6 */
  3149. resp -> group = group;
  3150. resp -> len = plen; /* 64-bit -- ramkrish */
  3151. /* Because this is a remote control packet, MiniportReserved
  3152. should not contain a pointer to a private protocol buffer. */
  3153. ASSERT(!MAIN_MINIPORT_FIELD(newp));
  3154. }
  3155. return newp;
  3156. } /* end Main_recv */
  3157. PNDIS_PACKET Main_recv_indicate (
  3158. PMAIN_CTXT ctxtp,
  3159. NDIS_HANDLE handle,
  3160. PUCHAR look_buf,
  3161. UINT look_len,
  3162. UINT packet_len,
  3163. PUCHAR head_buf,
  3164. UINT head_len,
  3165. PBOOLEAN accept)
  3166. {
  3167. PIP_HDR ip_hdrp;
  3168. PUCHAR tcp_hdrp;
  3169. USHORT sig = 0;
  3170. PMAIN_FRAME_HDR cvy_hdrp;
  3171. PUCHAR hdrp;
  3172. PNDIS_PACKET newp;
  3173. PMAIN_PROTOCOL_RESERVED resp = NULL;
  3174. PLIST_ENTRY entryp;
  3175. PMAIN_BUFFER bp;
  3176. NDIS_STATUS status;
  3177. ULONG op = MAIN_FILTER_OP_NONE;
  3178. ULONG len, xferred, off, dlen;
  3179. PNBT_HDR nbt_hdrp;
  3180. ULONG plen;
  3181. USHORT group;
  3182. ULONG packet_lowmark;
  3183. UINT offset;
  3184. /* find pointer to payload */
  3185. *accept = FALSE;
  3186. hdrp = Main_frame_find (ctxtp, head_buf, look_buf, look_len, & sig);
  3187. if (hdrp == NULL)
  3188. return NULL;
  3189. cvy_hdrp = (PMAIN_FRAME_HDR) hdrp;
  3190. /* V2.0.6 find out actual payload length (minus LLC/SNAP) */
  3191. plen = (ULONG)(packet_len - (hdrp - look_buf));
  3192. /* process IP frames */
  3193. if (sig == TCPIP_IP_SIG)
  3194. {
  3195. ip_hdrp = (PIP_HDR) hdrp;
  3196. tcp_hdrp = hdrp + sizeof (ULONG) * IP_GET_HLEN (ip_hdrp);
  3197. if (! Main_ip_recv_filter (ctxtp, ip_hdrp, tcp_hdrp, plen, & op))
  3198. return NULL;
  3199. }
  3200. /* process heartbeat frames */
  3201. else if ((sig == MAIN_FRAME_SIG || sig == MAIN_FRAME_SIG_OLD) &&
  3202. cvy_hdrp -> code == MAIN_FRAME_CODE)
  3203. {
  3204. /* make sure frame looks acceptable */
  3205. if (plen >= (sizeof (MAIN_FRAME_HDR) + sizeof (PING_MSG)))
  3206. {
  3207. /* V2.2 switch into backward compatibility mode if a convoy hearbeat
  3208. is detected */
  3209. if (sig == MAIN_FRAME_SIG_OLD && ! ctxtp -> etype_old)
  3210. {
  3211. if (ctxtp -> medium == NdisMedium802_3)
  3212. {
  3213. CVY_ETHERNET_ETYPE_SET (& ctxtp -> media_hdr . ethernet, MAIN_FRAME_SIG_OLD);
  3214. }
  3215. ctxtp -> etype_old = TRUE;
  3216. }
  3217. if (Main_recv_ping (ctxtp, cvy_hdrp))
  3218. {
  3219. #if defined (NLB_MIXED_MODE_CLUSTERS)
  3220. // code for migrating between cluster modes
  3221. /* reject the packet if the mac address is broadcast to allow unicast and multicast clusters to exist */
  3222. {
  3223. ULONG doff = CVY_MAC_DST_OFF (ctxtp -> medium);
  3224. if (ctxtp -> params . mcast_support &&
  3225. (! CVY_MAC_ADDR_COMP (ctxtp -> medium, head_buf + doff, & ctxtp -> cl_mac_addr)))
  3226. {
  3227. return NULL;
  3228. }
  3229. }
  3230. #endif /* NLB_MIXED_MODE_CLUSTERS */
  3231. /* V1.3.2b - if entire frame is in lookahead - let load deal with
  3232. it now */
  3233. #ifndef _WIN64 /* 64-bit -- ramkrish */
  3234. /* The data in the buffer may not be aligned. so copy the data into our own structure */
  3235. if (look_len == packet_len)
  3236. {
  3237. NdisAcquireSpinLock (& ctxtp -> load_lock);
  3238. if (ctxtp -> convoy_enabled)
  3239. Load_msg_rcv (& ctxtp -> load, (PPING_MSG) (cvy_hdrp + 1));
  3240. NdisReleaseSpinLock (& ctxtp -> load_lock);
  3241. }
  3242. /* get a fresh frame descriptor and perform data transfer */
  3243. else
  3244. #endif /* 64-bit -- ramkrish */
  3245. {
  3246. newp = Main_frame_get (ctxtp, FALSE, & len, MAIN_PACKET_TYPE_PING);
  3247. if (newp == NULL)
  3248. {
  3249. UNIV_PRINT (("error getting frame packet"));
  3250. return NULL;
  3251. }
  3252. NdisTransferData (& status, ctxtp -> mac_handle, handle, 0,
  3253. len, newp, & xferred);
  3254. if (status != NDIS_STATUS_PENDING)
  3255. Main_xfer_done (ctxtp, newp, status, xferred);
  3256. }
  3257. }
  3258. }
  3259. else
  3260. {
  3261. UNIV_PRINT (("PING message size mismatch %d vs %d", packet_len - (hdrp - look_buf), sizeof (MAIN_FRAME_HDR) + sizeof (PING_MSG)));
  3262. }
  3263. if (! ctxtp -> params . netmon_alive)
  3264. return NULL;
  3265. }
  3266. /* If statement added for NT 5.1 - ramkrish */
  3267. * accept = TRUE;
  3268. /* If the packet is being accepted and indicated to the protocol layer,
  3269. * then modify the destination mac address in multicast mode.
  3270. */
  3271. if (sig == TCPIP_IP_SIG && op == MAIN_FILTER_OP_NONE)
  3272. {
  3273. offset = CVY_MAC_DST_OFF(ctxtp -> medium);
  3274. if (ctxtp -> params . mcast_support &&
  3275. CVY_MAC_ADDR_COMP(ctxtp -> medium, head_buf + offset, & ctxtp -> cl_mac_addr) )
  3276. {
  3277. CVY_MAC_ADDR_COPY(ctxtp -> medium, head_buf + offset, & ctxtp -> ded_mac_addr);
  3278. }
  3279. return NULL;
  3280. }
  3281. /* The ARPs and NBT packets need to be modified */
  3282. /* V1.3.2b - get fresh packet */
  3283. /* shouse - On indicated receives, we need to use the MiniportReserved field to store
  3284. our private data. If allocation fails, bail out and dump the packet. CTRL packets
  3285. can continue to use ProtocolReserved because they never go up the stack. */
  3286. if (op != MAIN_FILTER_OP_CTRL) {
  3287. resp = (PMAIN_PROTOCOL_RESERVED) NdisAllocateFromNPagedLookasideList (& ctxtp -> resp_list);
  3288. if (!resp) {
  3289. * accept = FALSE; /* ###### no resources for the packet, so drop it */
  3290. return NULL;
  3291. }
  3292. }
  3293. newp = Main_packet_alloc (ctxtp, FALSE, & packet_lowmark);
  3294. if (newp == NULL)
  3295. {
  3296. * accept = FALSE; /* ###### cannot allocate packet, so drop it */
  3297. ctxtp -> cntr_recv_no_buf ++; /* V2.0.6 */
  3298. /* shouse - If we can't allocate a packet, put the private buffer back on the list. */
  3299. if (resp) NdisFreeToNPagedLookasideList (& ctxtp -> resp_list, resp);
  3300. return NULL;
  3301. }
  3302. /* get fresh buffer */
  3303. while (1)
  3304. {
  3305. NdisAcquireSpinLock (& ctxtp -> buf_lock);
  3306. entryp = RemoveHeadList (& ctxtp -> buf_list);
  3307. if (entryp != & ctxtp -> buf_list)
  3308. {
  3309. ctxtp->num_bufs_out++;
  3310. NdisReleaseSpinLock (& ctxtp -> buf_lock);
  3311. break;
  3312. }
  3313. NdisReleaseSpinLock (& ctxtp -> buf_lock);
  3314. UNIV_PRINT (("OUT OF BUFFERS!!!"));
  3315. if (! Main_bufs_alloc (ctxtp))
  3316. {
  3317. NdisFreePacket (newp);
  3318. ctxtp -> cntr_recv_no_buf ++; /* V2.0.6 */
  3319. * accept = FALSE; /* ###### no resources for the packet, so drop it */
  3320. /* shouse - If buffer allocation fails, put the resp buffer back on the list. */
  3321. if (resp) NdisFreeToNPagedLookasideList (& ctxtp -> resp_list, resp);
  3322. return NULL;
  3323. }
  3324. }
  3325. bp = CONTAINING_RECORD (entryp, MAIN_BUFFER, link);
  3326. UNIV_ASSERT (bp -> code == MAIN_BUFFER_CODE);
  3327. UNIV_ASSERT_VAL2 (head_len == ctxtp -> buf_mac_hdr_len, head_len, ctxtp -> buf_mac_hdr_len);
  3328. /* copy media header into the buffer */
  3329. NdisMoveMemory (bp -> data, head_buf, head_len);
  3330. /* V1.3.0b multicast support V1.3.1b */
  3331. off = CVY_MAC_DST_OFF (ctxtp -> medium);
  3332. /* V2.0.6 figure out frame type for statistics */
  3333. if (! CVY_MAC_ADDR_MCAST (ctxtp -> medium, head_buf + off))
  3334. group = MAIN_FRAME_DIRECTED;
  3335. else
  3336. {
  3337. if (CVY_MAC_ADDR_BCAST (ctxtp -> medium, head_buf + off))
  3338. group = MAIN_FRAME_BROADCAST;
  3339. else
  3340. group = MAIN_FRAME_MULTICAST;
  3341. }
  3342. /* mask cluster MAC address so not to confuse the protocol */
  3343. if (ctxtp -> params . mcast_support)
  3344. {
  3345. if (CVY_MAC_ADDR_COMP (ctxtp -> medium, bp -> data + off, & ctxtp -> cl_mac_addr))
  3346. CVY_MAC_ADDR_COPY (ctxtp -> medium, bp -> data + off, & ctxtp -> ded_mac_addr);
  3347. }
  3348. NdisAdjustBufferLength (bp -> full_bufp, head_len + packet_len);
  3349. /* only bother to transfer lookahead buffer if entire packet fits into
  3350. it - for some reason doing NdisTransferData with offset does not
  3351. work on some cards (ex. Intel 10 ISA) */
  3352. UNIV_ASSERT_VAL2 (packet_len <= ctxtp -> max_frame_size, packet_len, ctxtp -> max_frame_size);
  3353. if (look_len < packet_len)
  3354. {
  3355. NdisAdjustBufferLength (bp -> frame_bufp, packet_len);
  3356. NdisChainBufferAtFront (newp, bp -> frame_bufp);
  3357. }
  3358. else
  3359. {
  3360. UNIV_ASSERT_VAL2 (look_len <= ctxtp -> max_frame_size, look_len, ctxtp -> max_frame_size);
  3361. UNIV_ASSERT_VAL2 (bp -> framep == bp -> data + ctxtp -> buf_mac_hdr_len, (LONG_PTR) bp -> framep, (LONG_PTR) bp -> data);
  3362. NdisMoveMemory (bp -> framep, look_buf, look_len);
  3363. NdisChainBufferAtFront (newp, bp -> full_bufp);
  3364. }
  3365. /* after lookahead has been copied - do data modification. note that we
  3366. are assuming that frames that require modification fit in the lookahead
  3367. buffer */
  3368. if (sig == TCPIP_ARP_SIG)
  3369. {
  3370. UNIV_ASSERT_VAL2 (look_len == packet_len, look_len, packet_len);
  3371. /* recompute the offset from the beginning of frame */
  3372. hdrp = Main_frame_find (ctxtp, bp -> data, bp -> framep, look_len, & sig);
  3373. if (hdrp != NULL)
  3374. (void) Main_arp_handle (ctxtp, (PARP_HDR) hdrp, plen, FALSE); /* v2.0.6 */
  3375. }
  3376. if (op == MAIN_FILTER_OP_NBT)
  3377. {
  3378. UNIV_ASSERT_VAL2 (look_len == packet_len, look_len, packet_len);
  3379. /* recompute the offset from the beginning of frame */
  3380. hdrp = Main_frame_find (ctxtp, bp -> data, bp -> framep, look_len, & sig);
  3381. if (hdrp != NULL)
  3382. {
  3383. ip_hdrp = (PIP_HDR) hdrp;
  3384. tcp_hdrp = hdrp + sizeof (ULONG) * IP_GET_HLEN (ip_hdrp);
  3385. dlen = TCP_GET_DGRAM_LEN (ip_hdrp, (PTCP_HDR) tcp_hdrp);
  3386. nbt_hdrp = (PNBT_HDR) TCP_GET_DGRAM_PTR ((PTCP_HDR) tcp_hdrp);
  3387. if (plen >= (((PUCHAR) nbt_hdrp) - ((PUCHAR) ip_hdrp) + dlen)) /* v2.0.6 */
  3388. Tcpip_nbt_handle (& ctxtp -> tcpip, (PIP_HDR) hdrp, (PTCP_HDR) tcp_hdrp,
  3389. dlen, nbt_hdrp);
  3390. }
  3391. }
  3392. NDIS_SET_PACKET_HEADER_SIZE(newp, head_len);
  3393. /* setup protocol reserved fields */
  3394. /* shouse - For non-CTRL packets, Use MiniportReserved to store a pointer to our
  3395. private data. CTRL continues to use ProtocolReserved. */
  3396. if (op != MAIN_FILTER_OP_CTRL) {
  3397. MAIN_MINIPORT_FIELD (newp) = resp;
  3398. resp -> type = MAIN_PACKET_TYPE_INDICATE;
  3399. } else {
  3400. resp = MAIN_PROTOCOL_FIELD (newp);
  3401. resp -> type = MAIN_PACKET_TYPE_CTRL;
  3402. }
  3403. resp -> miscp = bp;
  3404. resp -> data = (LONG) (look_len < packet_len ? packet_len : 0); /* 64-bit -- ramkrish */
  3405. /* V2.0.6 */
  3406. resp -> len = plen; /* 64-bit -- ramkrish */
  3407. resp -> group = group;
  3408. /* if we have less than a half of allocation block number of buffers left -
  3409. allocate more until either alloc fails or we get above the watermark.
  3410. if alloc fails - mark packet so that it is not retained by the protocol
  3411. and is returned back to us. */
  3412. while (ctxtp->num_bufs_alloced - ctxtp->num_bufs_out < ctxtp->num_packets / 2)
  3413. {
  3414. if (!Main_bufs_alloc(ctxtp))
  3415. {
  3416. NDIS_SET_PACKET_STATUS (newp, NDIS_STATUS_RESOURCES);
  3417. return newp;
  3418. }
  3419. }
  3420. if (packet_lowmark)
  3421. NDIS_SET_PACKET_STATUS (newp, NDIS_STATUS_RESOURCES);
  3422. else
  3423. NDIS_SET_PACKET_STATUS (newp, NDIS_STATUS_SUCCESS);
  3424. if (op == MAIN_FILTER_OP_CTRL) {
  3425. /* Because this is a remote control packet, MiniportReserved
  3426. should not contain a pointer to a private protocol buffer. */
  3427. ASSERT(!MAIN_MINIPORT_FIELD(newp));
  3428. }
  3429. return newp;
  3430. } /* end Main_recv_indicate */
  3431. ULONG Main_actions_alloc (
  3432. PMAIN_CTXT ctxtp)
  3433. {
  3434. PMAIN_ACTION actp;
  3435. ULONG size, index, i;
  3436. NDIS_STATUS status;
  3437. NdisAcquireSpinLock (& ctxtp -> act_lock);
  3438. if (ctxtp -> num_action_allocs >= CVY_MAX_ALLOCS)
  3439. {
  3440. if (! ctxtp -> actions_warned)
  3441. {
  3442. LOG_MSG1 (MSG_WARN_RESOURCES, CVY_NAME_NUM_ACTIONS, ctxtp -> num_actions);
  3443. ctxtp -> actions_warned = TRUE;
  3444. }
  3445. NdisReleaseSpinLock (& ctxtp -> act_lock);
  3446. return FALSE;
  3447. }
  3448. index = ctxtp -> num_action_allocs;
  3449. NdisReleaseSpinLock (& ctxtp -> act_lock);
  3450. size = ctxtp -> num_actions * ctxtp -> act_size; /* 64-bit -- ramkrish */
  3451. status = NdisAllocateMemoryWithTag (& (ctxtp -> act_buf [index]), size,
  3452. UNIV_POOL_TAG);
  3453. if (status != NDIS_STATUS_SUCCESS)
  3454. {
  3455. UNIV_PRINT (("error allocating actions %d %x", size, status));
  3456. LOG_MSG2 (MSG_ERROR_MEMORY, MSG_NONE, size, status);
  3457. return FALSE;
  3458. }
  3459. NdisAcquireSpinLock (& ctxtp -> act_lock);
  3460. ctxtp -> num_action_allocs ++;
  3461. NdisReleaseSpinLock (& ctxtp -> act_lock);
  3462. for (i = 0; i < ctxtp -> num_actions; i++)
  3463. {
  3464. /* ensure that actp is aligned along 8-byte boundaries */
  3465. actp = (PMAIN_ACTION) ( (PUCHAR) (ctxtp -> act_buf [index]) + i * ctxtp -> act_size);
  3466. actp -> code = MAIN_ACTION_CODE;
  3467. actp -> ctxtp = ctxtp;
  3468. NdisInterlockedInsertTailList (& ctxtp -> act_list,
  3469. & actp -> link,
  3470. & ctxtp -> act_lock);
  3471. }
  3472. #if 0 /* 64-bit -- ramkrish */
  3473. for (i = 0, actp = ctxtp -> act_buf [index];
  3474. i < ctxtp -> num_actions;
  3475. i ++, actp ++)
  3476. {
  3477. actp -> code = MAIN_ACTION_CODE;
  3478. actp -> ctxtp = ctxtp;
  3479. NdisInterlockedInsertTailList (& ctxtp -> act_list,
  3480. & actp -> link,
  3481. & ctxtp -> act_lock);
  3482. }
  3483. #endif
  3484. return TRUE;
  3485. } /* end Main_actions_alloc */
  3486. PMAIN_ACTION Main_action_get (
  3487. PMAIN_CTXT ctxtp)
  3488. {
  3489. PLIST_ENTRY entryp;
  3490. PMAIN_ACTION actp;
  3491. while (1)
  3492. {
  3493. NdisAcquireSpinLock (& ctxtp -> act_lock);
  3494. entryp = RemoveHeadList (& ctxtp -> act_list);
  3495. NdisReleaseSpinLock (& ctxtp -> act_lock);
  3496. if (entryp != & ctxtp -> act_list)
  3497. break;
  3498. UNIV_PRINT (("OUT OF ACTIONS!!!"));
  3499. if (! Main_actions_alloc (ctxtp))
  3500. return NULL;
  3501. }
  3502. actp = CONTAINING_RECORD (entryp, MAIN_ACTION, link);
  3503. UNIV_ASSERT (actp -> code == MAIN_ACTION_CODE);
  3504. return actp;
  3505. } /* end Main_action_get */
  3506. VOID Main_action_put (
  3507. PMAIN_CTXT ctxtp,
  3508. PMAIN_ACTION actp)
  3509. {
  3510. UNIV_ASSERT (actp -> code == MAIN_ACTION_CODE);
  3511. NdisAcquireSpinLock (& ctxtp -> act_lock);
  3512. InsertTailList (& ctxtp -> act_list, & actp -> link);
  3513. NdisReleaseSpinLock (& ctxtp -> act_lock);
  3514. } /* end Main_action_put */
  3515. VOID Main_action_slow_put (
  3516. PMAIN_CTXT ctxtp,
  3517. PMAIN_ACTION actp)
  3518. {
  3519. UNIV_ASSERT (actp -> code == MAIN_ACTION_CODE);
  3520. NdisAcquireSpinLock (& ctxtp -> act_lock);
  3521. InsertTailList (& ctxtp -> act_list, & actp -> link);
  3522. NdisReleaseSpinLock (& ctxtp -> act_lock);
  3523. } /* end Main_action_slow_put */
  3524. ULONG Main_bufs_alloc (
  3525. PMAIN_CTXT ctxtp)
  3526. {
  3527. PMAIN_BUFFER bp;
  3528. NDIS_STATUS status;
  3529. ULONG i, size, index;
  3530. NdisAcquireSpinLock (& ctxtp -> buf_lock);
  3531. if (ctxtp -> num_buf_allocs >= CVY_MAX_ALLOCS)
  3532. {
  3533. if (! ctxtp -> packets_warned)
  3534. {
  3535. LOG_MSG1 (MSG_WARN_RESOURCES, CVY_NAME_NUM_PACKETS, ctxtp -> num_packets);
  3536. ctxtp -> packets_warned = TRUE;
  3537. }
  3538. NdisReleaseSpinLock (& ctxtp -> buf_lock);
  3539. return FALSE;
  3540. }
  3541. index = ctxtp -> num_buf_allocs;
  3542. NdisReleaseSpinLock (& ctxtp -> buf_lock);
  3543. /* get twice as many buffer descriptors (one for entire buffer and one
  3544. just for the payload portion) */
  3545. size = 2 * ctxtp -> num_packets;
  3546. NdisAllocateBufferPool (& status, & (ctxtp -> buf_pool_handle [index]),
  3547. 2 * ctxtp -> num_packets);
  3548. if (status != NDIS_STATUS_SUCCESS)
  3549. {
  3550. UNIV_PRINT (("error allocating buffer pool %d %x", size, status));
  3551. LOG_MSG2 (MSG_ERROR_MEMORY, MSG_NONE, size, status);
  3552. return FALSE;
  3553. }
  3554. /* allocate memory for the payload */
  3555. size = ctxtp -> num_packets * ctxtp -> buf_size;
  3556. status = NdisAllocateMemoryWithTag (& (ctxtp -> buf_array [index]), size,
  3557. UNIV_POOL_TAG);
  3558. if (status != NDIS_STATUS_SUCCESS)
  3559. {
  3560. UNIV_PRINT (("error allocating buffer space %d %x", size, status));
  3561. LOG_MSG2 (MSG_ERROR_MEMORY, MSG_NONE, size, status);
  3562. goto error;
  3563. }
  3564. NdisZeroMemory (ctxtp -> buf_array [index], size);
  3565. for (i = 0; i < ctxtp -> num_packets; i ++)
  3566. {
  3567. bp = (PMAIN_BUFFER) (ctxtp -> buf_array [index] + i * ctxtp -> buf_size);
  3568. bp -> code = MAIN_BUFFER_CODE;
  3569. /* setup buffer descriptors to describe entire buffer and just the
  3570. payload */
  3571. size = ctxtp -> buf_mac_hdr_len + ctxtp -> max_frame_size;
  3572. NdisAllocateBuffer (& status, & bp -> full_bufp,
  3573. ctxtp -> buf_pool_handle [index],
  3574. bp -> data, size);
  3575. if (status != NDIS_STATUS_SUCCESS)
  3576. {
  3577. UNIV_PRINT (("error allocating header buffer %d %x", i, status));
  3578. LOG_MSG3 (MSG_ERROR_MEMORY, MSG_NONE, i, size, status);
  3579. goto error;
  3580. }
  3581. bp -> framep = bp -> data + ctxtp -> buf_mac_hdr_len;
  3582. size = ctxtp -> max_frame_size;
  3583. NdisAllocateBuffer (& status, & bp -> frame_bufp,
  3584. ctxtp -> buf_pool_handle [index],
  3585. bp -> framep, size);
  3586. if (status != NDIS_STATUS_SUCCESS)
  3587. {
  3588. UNIV_PRINT (("error allocating frame buffer %d %x", i, status));
  3589. LOG_MSG3 (MSG_ERROR_MEMORY, MSG_NONE, i, size, status);
  3590. goto error;
  3591. }
  3592. NdisInterlockedInsertTailList (& ctxtp -> buf_list,
  3593. & bp -> link,
  3594. & ctxtp -> buf_lock);
  3595. }
  3596. NdisAcquireSpinLock (& ctxtp -> buf_lock);
  3597. ctxtp -> num_buf_allocs ++;
  3598. ctxtp->num_bufs_alloced += ctxtp->num_packets;
  3599. NdisReleaseSpinLock (& ctxtp -> buf_lock);
  3600. return TRUE;
  3601. error:
  3602. if (ctxtp -> buf_array [index] != NULL)
  3603. {
  3604. for (i = 0; i < ctxtp -> num_packets; i ++)
  3605. {
  3606. bp = (PMAIN_BUFFER) (ctxtp -> buf_array [index] + i * ctxtp -> buf_size);
  3607. if (bp -> full_bufp != NULL)
  3608. {
  3609. NdisAdjustBufferLength (bp -> full_bufp,
  3610. ctxtp -> buf_mac_hdr_len +
  3611. ctxtp -> max_frame_size);
  3612. NdisFreeBuffer (bp -> full_bufp);
  3613. }
  3614. if (bp -> frame_bufp != NULL)
  3615. {
  3616. NdisAdjustBufferLength (bp -> frame_bufp,
  3617. ctxtp -> max_frame_size);
  3618. NdisFreeBuffer (bp -> frame_bufp);
  3619. }
  3620. }
  3621. NdisFreeMemory (ctxtp -> buf_array [index],
  3622. ctxtp -> num_packets * ctxtp -> buf_size, 0);
  3623. }
  3624. if (ctxtp -> buf_pool_handle [index] != NULL)
  3625. NdisFreeBufferPool (ctxtp -> buf_pool_handle [index]);
  3626. return FALSE;
  3627. } /* end Main_bufs_alloc */
  3628. PNDIS_PACKET Main_frame_get (
  3629. PMAIN_CTXT ctxtp,
  3630. ULONG send,
  3631. PULONG lenp,
  3632. USHORT frame_type)
  3633. {
  3634. PLIST_ENTRY entryp;
  3635. PMAIN_FRAME_DSCR dscrp;
  3636. NDIS_STATUS status;
  3637. PMAIN_PROTOCOL_RESERVED resp;
  3638. PNDIS_PACKET packet;
  3639. PNDIS_PACKET_STACK pktstk;
  3640. BOOLEAN stack_left;
  3641. NdisAllocatePacket (& status, & packet, ctxtp -> frame_pool_handle);
  3642. if (status != NDIS_STATUS_SUCCESS)
  3643. {
  3644. UNIV_PRINT (("OUT OF PING PACKETS!!!"));
  3645. #if 0 /* V1.3.2b */
  3646. if (! ctxtp -> send_msgs_warned)
  3647. {
  3648. LOG_MSG1 (MSG_WARN_RESOURCES, CVY_NAME_NUM_SEND_MSGS, ctxtp -> num_send_msgs);
  3649. ctxtp -> send_msgs_warned = TRUE;
  3650. }
  3651. #endif
  3652. return NULL;
  3653. }
  3654. /* #ps# -- ramkrish */
  3655. pktstk = NdisIMGetCurrentPacketStack (packet, & stack_left);
  3656. if (pktstk)
  3657. {
  3658. MAIN_IMRESERVED_FIELD(pktstk) = NULL;
  3659. }
  3660. /* Make sure that the MiniportReserved field is initially NULL. */
  3661. MAIN_MINIPORT_FIELD(packet) = NULL;
  3662. NdisAcquireSpinLock (& ctxtp -> frame_lock);
  3663. entryp = RemoveHeadList (& ctxtp -> frame_list);
  3664. NdisReleaseSpinLock (& ctxtp -> frame_lock);
  3665. if (entryp == & ctxtp -> frame_list)
  3666. {
  3667. UNIV_PRINT (("OUT OF PING MESSAGES!!!"));
  3668. #if 0 /* V1.3.2b */
  3669. if (! ctxtp -> send_msgs_warned)
  3670. {
  3671. LOG_MSG1 (MSG_WARN_RESOURCES, CVY_NAME_NUM_SEND_MSGS, ctxtp -> num_send_msgs);
  3672. ctxtp -> send_msgs_warned = TRUE;
  3673. }
  3674. #endif
  3675. NdisFreePacket (packet);
  3676. return NULL;
  3677. }
  3678. dscrp = CONTAINING_RECORD (entryp, MAIN_FRAME_DSCR, link);
  3679. /* if sending heartbeat - fill out the header. in both cases - chain
  3680. the necessary buffer descriptors to the packet */
  3681. if (send)
  3682. {
  3683. PVOID address = NULL;
  3684. ULONG size = 0;
  3685. UNIV_ASSERT_VAL (frame_type == MAIN_PACKET_TYPE_PING ||
  3686. frame_type == MAIN_PACKET_TYPE_IGMP,
  3687. frame_type);
  3688. /* V2.0.6, V2.2 moved here */
  3689. /* Differentiate between igmp and heartbeat messages and allocate buffers */
  3690. if (frame_type == MAIN_PACKET_TYPE_PING)
  3691. {
  3692. size = sizeof (PING_MSG);
  3693. address = (PVOID)(ctxtp -> load_msgp);
  3694. }
  3695. else if (frame_type == MAIN_PACKET_TYPE_IGMP)
  3696. {
  3697. size = sizeof (MAIN_IGMP_FRAME);
  3698. address = (PVOID) (& ctxtp -> igmp_frame);
  3699. }
  3700. else
  3701. {
  3702. UNIV_PRINT (("Invalid frame type passed to Main_frame_get 0x%x", frame_type));
  3703. UNIV_ASSERT(0);
  3704. }
  3705. /* Allocate the buffer for sending the data */
  3706. NdisAllocateBuffer (& status, & dscrp -> send_data_bufp,
  3707. ctxtp -> frame_buf_pool_handle,
  3708. address, size);
  3709. if (status != NDIS_STATUS_SUCCESS)
  3710. {
  3711. UNIV_PRINT (("Failed to allocate buffer for 0x%x", frame_type));
  3712. dscrp -> send_data_bufp = NULL;
  3713. NdisAcquireSpinLock (& ctxtp -> frame_lock);
  3714. InsertTailList (& ctxtp -> frame_list, & dscrp -> link);
  3715. NdisReleaseSpinLock (& ctxtp -> frame_lock);
  3716. NdisFreePacket (packet);
  3717. return NULL;
  3718. }
  3719. /* since packet length is always the same, and so are destination
  3720. and source addresses - can use generic media header */
  3721. if (frame_type == MAIN_PACKET_TYPE_PING)
  3722. {
  3723. dscrp -> media_hdr = ctxtp -> media_hdr;
  3724. dscrp -> frame_hdr . code = MAIN_FRAME_CODE;
  3725. dscrp -> frame_hdr . version = CVY_VERSION_FULL;
  3726. dscrp -> frame_hdr . host = (UCHAR) ctxtp -> params . host_priority;
  3727. dscrp -> frame_hdr . cl_ip_addr = ctxtp -> cl_ip_addr;
  3728. dscrp -> frame_hdr . ded_ip_addr = ctxtp -> ded_ip_addr;
  3729. NdisChainBufferAtFront (packet, dscrp -> send_data_bufp); /* V1.1.4 */
  3730. NdisChainBufferAtFront (packet, dscrp -> frame_hdr_bufp);
  3731. }
  3732. else if (frame_type == MAIN_PACKET_TYPE_IGMP)
  3733. {
  3734. dscrp -> media_hdr = ctxtp -> media_hdr_igmp;
  3735. NdisChainBufferAtFront (packet, dscrp -> send_data_bufp); /* V1.1.4 */
  3736. }
  3737. else
  3738. {
  3739. UNIV_PRINT (("Invalid frame type passed to Main_frame_get 0x%x", frame_type));
  3740. UNIV_ASSERT(0);
  3741. }
  3742. NdisChainBufferAtFront (packet, dscrp -> media_hdr_bufp);
  3743. }
  3744. else
  3745. {
  3746. NdisChainBufferAtFront (packet, dscrp -> recv_data_bufp); /* V1.1.4 */
  3747. NdisChainBufferAtFront (packet, dscrp -> frame_hdr_bufp);
  3748. }
  3749. /* fill out protocol reserved fields */
  3750. /* shouse - Again, since these packets are hidden from upper layers, we should
  3751. be OK using the protocol reserved field regardless of send/receive. */
  3752. resp = MAIN_PROTOCOL_FIELD (packet);
  3753. resp -> type = frame_type;
  3754. resp -> miscp = dscrp;
  3755. resp -> data = 0;
  3756. resp -> len = 0;
  3757. resp -> group = 0;
  3758. * lenp = dscrp -> recv_len;
  3759. return packet;
  3760. } /* end Main_frame_get */
  3761. VOID Main_frame_put (
  3762. PMAIN_CTXT ctxtp,
  3763. PNDIS_PACKET packet,
  3764. PMAIN_FRAME_DSCR dscrp)
  3765. {
  3766. PNDIS_BUFFER bufp;
  3767. /* shouse - Again, since these packets are hidden from upper layers, we should
  3768. be OK using the protocol reserved field regardless of send/receive. */
  3769. PMAIN_PROTOCOL_RESERVED resp = MAIN_PROTOCOL_FIELD (packet);
  3770. UNIV_ASSERT_VAL (resp -> type == MAIN_PACKET_TYPE_PING ||
  3771. resp -> type == MAIN_PACKET_TYPE_IGMP, resp -> type);
  3772. /* strip buffers from the packet buffer chain */
  3773. do
  3774. {
  3775. NdisUnchainBufferAtFront (packet, & bufp);
  3776. }
  3777. while (bufp != NULL);
  3778. /* recyle the packet */
  3779. NdisReinitializePacket (packet);
  3780. NdisFreePacket (packet);
  3781. /* If the send buffer is not null, free this buffer */
  3782. if (dscrp -> send_data_bufp != NULL)
  3783. {
  3784. NdisFreeBuffer (dscrp -> send_data_bufp);
  3785. dscrp -> send_data_bufp = NULL;
  3786. }
  3787. /* put frame descriptor back on the free list */
  3788. NdisAcquireSpinLock (& ctxtp -> frame_lock);
  3789. InsertTailList (& ctxtp -> frame_list, & dscrp -> link);
  3790. NdisReleaseSpinLock (& ctxtp -> frame_lock);
  3791. } /* end Main_frame_return */
  3792. PNDIS_PACKET Main_packet_alloc (
  3793. PMAIN_CTXT ctxtp,
  3794. ULONG send,
  3795. PULONG low)
  3796. {
  3797. PNDIS_PACKET newp = NULL;
  3798. PNDIS_HANDLE poolh;
  3799. ULONG i, max, size, start;
  3800. NDIS_STATUS status;
  3801. PNDIS_PACKET_STACK pktstk;
  3802. BOOLEAN stack_left;
  3803. /* !!! assume that recv and send paths are not re-entrant, otherwise need
  3804. to lock this. make sure that NdisAllocatePacket... routines are not
  3805. called holding a spin lock */
  3806. /* V1.1.2 */
  3807. *low = FALSE;
  3808. if (send)
  3809. {
  3810. poolh = ctxtp -> send_pool_handle;
  3811. NdisAcquireSpinLock (& ctxtp -> send_lock);
  3812. max = ctxtp -> num_send_packet_allocs;
  3813. start = ctxtp -> cur_send_packet_pool;
  3814. ctxtp -> cur_send_packet_pool = (start + 1) % max;
  3815. NdisReleaseSpinLock (& ctxtp -> send_lock);
  3816. }
  3817. else
  3818. {
  3819. poolh = ctxtp -> recv_pool_handle;
  3820. NdisAcquireSpinLock (& ctxtp -> recv_lock);
  3821. max = ctxtp -> num_recv_packet_allocs;
  3822. start = ctxtp -> cur_recv_packet_pool;
  3823. ctxtp -> cur_recv_packet_pool = (start + 1) % max;
  3824. NdisReleaseSpinLock (& ctxtp -> recv_lock);
  3825. }
  3826. /* Try to allocate a packet from the existing packet pools */
  3827. i = start;
  3828. do
  3829. {
  3830. NdisAllocatePacket (& status, & newp, poolh [i]);
  3831. if (status == NDIS_STATUS_SUCCESS)
  3832. {
  3833. /* #ps# -- ramkrish */
  3834. pktstk = NdisIMGetCurrentPacketStack (newp, & stack_left);
  3835. if (pktstk)
  3836. {
  3837. MAIN_IMRESERVED_FIELD (pktstk) = NULL;
  3838. }
  3839. /* Make sure that the MiniportReserved field is initially NULL. */
  3840. MAIN_MINIPORT_FIELD(newp) = NULL;
  3841. if (send)
  3842. {
  3843. NdisAcquireSpinLock (& ctxtp -> send_lock);
  3844. /* Because the decrement is interlocked, so should the increment. */
  3845. NdisInterlockedIncrement(& ctxtp -> num_sends_out);
  3846. if ((ctxtp -> num_sends_alloced - ctxtp -> num_sends_out)
  3847. < (ctxtp -> num_packets / 2))
  3848. {
  3849. NdisReleaseSpinLock (& ctxtp -> send_lock);
  3850. break;
  3851. }
  3852. NdisReleaseSpinLock (& ctxtp -> send_lock);
  3853. }
  3854. else
  3855. {
  3856. NdisAcquireSpinLock (& ctxtp -> recv_lock);
  3857. /* Because the decrement is interlocked, so should the increment. */
  3858. NdisInterlockedIncrement(& ctxtp -> num_recvs_out);
  3859. if ((ctxtp -> num_recvs_alloced - ctxtp -> num_recvs_out)
  3860. < (ctxtp -> num_packets / 2))
  3861. {
  3862. NdisReleaseSpinLock (& ctxtp -> recv_lock);
  3863. break;
  3864. }
  3865. NdisReleaseSpinLock (& ctxtp -> recv_lock);
  3866. }
  3867. return newp;
  3868. }
  3869. /* pick the next pool to improve number of tries until we get something */
  3870. i = (i + 1) % max;
  3871. } while (i != start);
  3872. /* At this point, the high level mark has been reached, so allocate a new packet pool */
  3873. if (send)
  3874. {
  3875. NdisAcquireSpinLock (& ctxtp -> send_lock);
  3876. if (ctxtp -> num_send_packet_allocs >= CVY_MAX_ALLOCS)
  3877. {
  3878. * low = TRUE;
  3879. NdisReleaseSpinLock (& ctxtp -> send_lock);
  3880. return newp;
  3881. }
  3882. if (ctxtp -> send_allocing)
  3883. {
  3884. * low = TRUE; /* do not know whether the allocation by another thread will succeed or not */
  3885. NdisReleaseSpinLock (& ctxtp -> send_lock);
  3886. return newp;
  3887. }
  3888. else
  3889. {
  3890. max = ctxtp -> num_send_packet_allocs;
  3891. ctxtp -> send_allocing = TRUE;
  3892. NdisReleaseSpinLock (& ctxtp -> send_lock);
  3893. }
  3894. }
  3895. else
  3896. {
  3897. NdisAcquireSpinLock (& ctxtp -> recv_lock);
  3898. if (ctxtp -> num_recv_packet_allocs >= CVY_MAX_ALLOCS)
  3899. {
  3900. * low = TRUE;
  3901. NdisReleaseSpinLock (& ctxtp -> recv_lock);
  3902. return newp;
  3903. }
  3904. if (ctxtp -> recv_allocing)
  3905. {
  3906. * low = TRUE; /* do not know whether the allocation by another thread will succeed or not */
  3907. NdisReleaseSpinLock (& ctxtp -> recv_lock);
  3908. return newp;
  3909. }
  3910. else
  3911. {
  3912. max = ctxtp -> num_recv_packet_allocs;
  3913. ctxtp -> recv_allocing = TRUE;
  3914. NdisReleaseSpinLock (& ctxtp -> recv_lock);
  3915. }
  3916. }
  3917. /* Due to the send_allocing and recv_allocing flag, at most 1 send or recv thread will be in this portion at any time */
  3918. size = ctxtp -> num_packets;
  3919. NdisAllocatePacketPool (& status, & (poolh [max]),
  3920. ctxtp -> num_packets,
  3921. sizeof (MAIN_PROTOCOL_RESERVED));
  3922. if (status != NDIS_STATUS_SUCCESS)
  3923. {
  3924. if (send)
  3925. {
  3926. UNIV_PRINT (("error allocating send packet pool %d %x", size, status));
  3927. }
  3928. else
  3929. {
  3930. UNIV_PRINT (("error allocating recv packet pool %d %x", size, status));
  3931. }
  3932. LOG_MSG2 (MSG_ERROR_MEMORY, MSG_NONE, size, status);
  3933. * low = TRUE;
  3934. }
  3935. else
  3936. {
  3937. if (send)
  3938. {
  3939. NdisAcquireSpinLock (& ctxtp -> send_lock);
  3940. ctxtp -> num_send_packet_allocs ++;
  3941. ctxtp -> num_sends_alloced += ctxtp -> num_packets;
  3942. ctxtp -> send_allocing = FALSE;
  3943. NdisReleaseSpinLock (& ctxtp -> send_lock);
  3944. }
  3945. else
  3946. {
  3947. NdisAcquireSpinLock (& ctxtp -> recv_lock);
  3948. ctxtp -> num_recv_packet_allocs ++;
  3949. ctxtp -> num_recvs_alloced += ctxtp -> num_packets;
  3950. ctxtp -> recv_allocing = FALSE;
  3951. NdisReleaseSpinLock (& ctxtp -> recv_lock);
  3952. }
  3953. * low = FALSE;
  3954. }
  3955. return newp;
  3956. } /* Main_packet_alloc */
  3957. /* V1.3.2b */
  3958. #if 0
  3959. PNDIS_PACKET Main_packet_alloc (
  3960. PMAIN_CTXT ctxtp,
  3961. ULONG send)
  3962. {
  3963. PNDIS_PACKET newp;
  3964. PNDIS_HANDLE poolh;
  3965. ULONG i, max, size, start;
  3966. NDIS_STATUS status;
  3967. /* !!! assume that recv and send paths are not re-entrant, otherwise need
  3968. to lock this. make sure that NdisAllocatePacket... routines are not
  3969. called holding a spin lock */
  3970. /* V1.1.2 */
  3971. if (send)
  3972. {
  3973. poolh = ctxtp -> send_pool_handle;
  3974. NdisAcquireSpinLock (& ctxtp -> send_lock);
  3975. max = ctxtp -> num_send_packet_allocs;
  3976. start = ctxtp -> cur_send_packet_pool;
  3977. ctxtp -> cur_send_packet_pool = (start + 1) % max;
  3978. NdisReleaseSpinLock (& ctxtp -> send_lock);
  3979. }
  3980. else
  3981. {
  3982. poolh = ctxtp -> recv_pool_handle;
  3983. NdisAcquireSpinLock (& ctxtp -> recv_lock);
  3984. max = ctxtp -> num_recv_packet_allocs;
  3985. start = ctxtp -> cur_recv_packet_pool;
  3986. ctxtp -> cur_recv_packet_pool = (start + 1) % max;
  3987. NdisReleaseSpinLock (& ctxtp -> recv_lock);
  3988. }
  3989. i = start;
  3990. while (1)
  3991. {
  3992. NdisAllocatePacket (& status, & newp, poolh [i]);
  3993. if (status == NDIS_STATUS_SUCCESS)
  3994. {
  3995. if (send)
  3996. NdisInterlockedIncrement(& ctxtp -> num_sends_out);
  3997. else
  3998. NdisInterlockedIncrement(& ctxtp -> num_recvs_out);
  3999. return newp;
  4000. }
  4001. /* pick the next pool to improve number of tries until we get something */
  4002. i = (i + 1) % max;
  4003. if (i != start)
  4004. continue;
  4005. if (send)
  4006. {
  4007. UNIV_PRINT (("OUT OF SEND PACKETS!!!"));
  4008. }
  4009. else
  4010. {
  4011. UNIV_PRINT (("OUT OF RECV PACKETS!!!"));
  4012. }
  4013. /* allocate another packet pool if we can */
  4014. if (max >= CVY_MAX_ALLOCS)
  4015. {
  4016. if (! ctxtp -> packets_warned)
  4017. {
  4018. LOG_MSG1 (MSG_WARN_RESOURCES, CVY_NAME_NUM_PACKETS, ctxtp -> num_packets);
  4019. ctxtp -> packets_warned = TRUE;
  4020. }
  4021. break;
  4022. }
  4023. size = ctxtp -> num_packets;
  4024. NdisAllocatePacketPool (& status, & (poolh [max]),
  4025. ctxtp -> num_packets,
  4026. sizeof (MAIN_PROTOCOL_RESERVED));
  4027. if (status != NDIS_STATUS_SUCCESS)
  4028. {
  4029. UNIV_PRINT (("error allocating recv packet pool %d %x", size, status));
  4030. LOG_MSG2 (MSG_ERROR_MEMORY, MSG_NONE, size, status);
  4031. break;
  4032. }
  4033. if (send)
  4034. {
  4035. NdisAcquireSpinLock (& ctxtp -> send_lock);
  4036. ctxtp -> num_send_packet_allocs ++;
  4037. ctxtp -> cur_send_packet_pool = max;
  4038. ctxtp -> num_sends_alloced += ctxtp->num_packets;
  4039. NdisReleaseSpinLock (& ctxtp -> send_lock);
  4040. }
  4041. else
  4042. {
  4043. NdisAcquireSpinLock (& ctxtp -> recv_lock);
  4044. ctxtp -> num_recv_packet_allocs ++;
  4045. ctxtp -> cur_recv_packet_pool = max;
  4046. ctxtp -> num_recvs_alloced += ctxtp->num_packets;
  4047. NdisReleaseSpinLock (& ctxtp -> recv_lock);
  4048. }
  4049. i = max;
  4050. max ++;
  4051. }
  4052. return NULL;
  4053. } /* end Main_packet_alloc */
  4054. #endif
  4055. PNDIS_PACKET Main_packet_get (
  4056. PMAIN_CTXT ctxtp,
  4057. PNDIS_PACKET packet,
  4058. ULONG send,
  4059. USHORT group,
  4060. ULONG len)
  4061. {
  4062. PNDIS_PACKET newp;
  4063. // PNDIS_PACKET_OOB_DATA new_oobp, old_oobp;
  4064. PMAIN_PROTOCOL_RESERVED resp = NULL;
  4065. ULONG packet_lowmark;
  4066. PNDIS_PACKET_STACK pktstk = NULL;
  4067. BOOLEAN stack_left;
  4068. /* #ps# */
  4069. pktstk = NdisIMGetCurrentPacketStack (packet, & stack_left);
  4070. if (stack_left)
  4071. {
  4072. resp = (PMAIN_PROTOCOL_RESERVED) NdisAllocateFromNPagedLookasideList (& ctxtp -> resp_list);
  4073. MAIN_IMRESERVED_FIELD (pktstk) = resp;
  4074. if (resp)
  4075. {
  4076. resp -> type = MAIN_PACKET_TYPE_PASS;
  4077. resp -> miscp = packet;
  4078. resp -> data = 0;
  4079. /* V2.0.6 */
  4080. resp -> group = group;
  4081. resp -> len = len; /* 64-bit -- ramkrish */
  4082. return packet;
  4083. }
  4084. }
  4085. /* get a packet */
  4086. /* shouse - If this is a receive, then we are using MiniportReserved and must allocate a
  4087. buffer to hold our private data. If it fails, bail out and dump the packet. */
  4088. if (!send) {
  4089. resp = (PMAIN_PROTOCOL_RESERVED) NdisAllocateFromNPagedLookasideList (& ctxtp -> resp_list);
  4090. if (!resp) return NULL;
  4091. }
  4092. newp = Main_packet_alloc (ctxtp, send, & packet_lowmark);
  4093. if (newp == NULL) {
  4094. /* shouse - If packet allocation fails, put the resp buffer back on the list if this is a receive. */
  4095. if (resp) NdisFreeToNPagedLookasideList (& ctxtp -> resp_list, resp);
  4096. return NULL;
  4097. }
  4098. pktstk = NdisIMGetCurrentPacketStack (newp, & stack_left); /* #ps# */
  4099. if (pktstk)
  4100. {
  4101. MAIN_IMRESERVED_FIELD(pktstk) = NULL;
  4102. }
  4103. /* Make sure that the MiniportReserved field is initially NULL. */
  4104. MAIN_MINIPORT_FIELD(newp) = NULL;
  4105. /* make new packet resemble the outside one */
  4106. if (send)
  4107. {
  4108. PVOID media_info = NULL;
  4109. ULONG media_info_size = 0;
  4110. newp->Private.Head = packet->Private.Head;
  4111. newp->Private.Tail = packet->Private.Tail;
  4112. NdisGetPacketFlags(newp) = NdisGetPacketFlags(packet);
  4113. NdisSetPacketFlags(newp, NDIS_FLAGS_DONT_LOOPBACK);
  4114. // Copy the OOB Offset from the original packet to the new
  4115. // packet.
  4116. NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(newp),
  4117. NDIS_OOB_DATA_FROM_PACKET(packet),
  4118. sizeof(NDIS_PACKET_OOB_DATA));
  4119. // Copy the per packet info into the new packet
  4120. NdisIMCopySendPerPacketInfo(newp, packet);
  4121. // Copy the Media specific information
  4122. NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(packet, & media_info, & media_info_size);
  4123. if (media_info != NULL || media_info_size != 0)
  4124. {
  4125. NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(newp, media_info, media_info_size);
  4126. }
  4127. }
  4128. else
  4129. {
  4130. newp->Private.Head = packet->Private.Head;
  4131. newp->Private.Tail = packet->Private.Tail;
  4132. // Get the original packet(it could be the same packet as one received or a different one
  4133. // based on # of layered MPs) and set it on the indicated packet so the OOB stuff is visible
  4134. // correctly at the top.
  4135. NDIS_SET_ORIGINAL_PACKET(newp, NDIS_GET_ORIGINAL_PACKET(packet));
  4136. NDIS_SET_PACKET_HEADER_SIZE(newp, NDIS_GET_PACKET_HEADER_SIZE(packet));
  4137. NdisGetPacketFlags(newp) = NdisGetPacketFlags(packet);
  4138. if (packet_lowmark)
  4139. NDIS_SET_PACKET_STATUS(newp, NDIS_STATUS_RESOURCES);
  4140. else
  4141. NDIS_SET_PACKET_STATUS(newp, NDIS_GET_PACKET_STATUS(packet));
  4142. }
  4143. #if 0
  4144. newp -> Private . PhysicalCount = packet -> Private . PhysicalCount;
  4145. newp -> Private . TotalLength = packet -> Private . TotalLength;
  4146. newp -> Private . Head = packet -> Private . Head;
  4147. newp -> Private . Tail = packet -> Private . Tail;
  4148. newp -> Private . Count = packet -> Private . Count;
  4149. newp -> Private . Flags = packet -> Private . Flags;
  4150. newp -> Private . ValidCounts = packet -> Private . ValidCounts;
  4151. newp -> Private . NdisPacketFlags = packet -> Private . NdisPacketFlags;
  4152. old_oobp = NDIS_OOB_DATA_FROM_PACKET (packet);
  4153. new_oobp = NDIS_OOB_DATA_FROM_PACKET (newp);
  4154. * new_oobp = * old_oobp;
  4155. #endif
  4156. /* fill out protocol reserved field */
  4157. /* shouse - Sends should use ProtocolReserved and receives should use MiniportReserved. Buffer
  4158. space for MiniportReserved is allocated further up in this function. */
  4159. if (send) {
  4160. resp = MAIN_PROTOCOL_FIELD (newp);
  4161. } else {
  4162. MAIN_MINIPORT_FIELD (newp) = resp;
  4163. }
  4164. resp -> type = MAIN_PACKET_TYPE_PASS;
  4165. resp -> miscp = packet;
  4166. resp -> data = 0;
  4167. /* V2.0.6 */
  4168. resp -> group = group;
  4169. resp -> len = len; /* 64-bit -- ramkrish */
  4170. return newp;
  4171. } /* end Main_packet_get*/
  4172. PNDIS_PACKET Main_packet_put (
  4173. PMAIN_CTXT ctxtp,
  4174. PNDIS_PACKET packet,
  4175. ULONG send,
  4176. NDIS_STATUS status)
  4177. {
  4178. PNDIS_PACKET oldp = NULL;
  4179. PNDIS_PACKET_STACK pktstk;
  4180. BOOLEAN stack_left;
  4181. PMAIN_PROTOCOL_RESERVED resp; /* #ps# */
  4182. // PMAIN_PROTOCOL_RESERVED resp = MAIN_PROTOCOL_FIELD (packet);
  4183. PMAIN_BUFFER bp;
  4184. PNDIS_BUFFER bufp;
  4185. /* #ps# */
  4186. MAIN_RESP_FIELD(packet, stack_left, pktstk, resp, send);
  4187. UNIV_ASSERT(resp);
  4188. /* Because CTRL packets are actually allocated on the receive path,
  4189. we need to change the send flag to false to get the logic right. */
  4190. if (resp->type == MAIN_PACKET_TYPE_CTRL) {
  4191. ASSERT(send);
  4192. send = FALSE;
  4193. }
  4194. /* V2.0.6 update statistics */
  4195. if (send)
  4196. {
  4197. if (status == NDIS_STATUS_SUCCESS)
  4198. {
  4199. ctxtp -> cntr_xmit_ok ++;
  4200. switch (resp -> group)
  4201. {
  4202. case MAIN_FRAME_DIRECTED:
  4203. ctxtp -> cntr_xmit_frames_dir ++;
  4204. ctxtp -> cntr_xmit_bytes_dir += (ULONGLONG) (resp -> len);
  4205. break;
  4206. case MAIN_FRAME_MULTICAST:
  4207. ctxtp -> cntr_xmit_frames_mcast ++;
  4208. ctxtp -> cntr_xmit_bytes_mcast += (ULONGLONG) (resp -> len);
  4209. break;
  4210. case MAIN_FRAME_BROADCAST:
  4211. ctxtp -> cntr_xmit_frames_bcast ++;
  4212. ctxtp -> cntr_xmit_bytes_bcast += (ULONGLONG) (resp -> len);
  4213. break;
  4214. default:
  4215. break;
  4216. }
  4217. }
  4218. else
  4219. ctxtp -> cntr_xmit_err ++;
  4220. }
  4221. else
  4222. {
  4223. if (status == NDIS_STATUS_SUCCESS)
  4224. {
  4225. ctxtp -> cntr_recv_ok ++;
  4226. switch (resp -> group)
  4227. {
  4228. case MAIN_FRAME_DIRECTED:
  4229. ctxtp -> cntr_recv_frames_dir ++;
  4230. ctxtp -> cntr_recv_bytes_dir += (ULONGLONG) (resp -> len);
  4231. break;
  4232. case MAIN_FRAME_MULTICAST:
  4233. ctxtp -> cntr_recv_frames_mcast ++;
  4234. ctxtp -> cntr_recv_bytes_mcast += (ULONGLONG) (resp -> len);
  4235. break;
  4236. case MAIN_FRAME_BROADCAST:
  4237. ctxtp -> cntr_recv_frames_bcast ++;
  4238. ctxtp -> cntr_recv_bytes_bcast += (ULONGLONG) (resp -> len);
  4239. break;
  4240. default:
  4241. break;
  4242. }
  4243. }
  4244. else
  4245. ctxtp -> cntr_recv_err ++;
  4246. }
  4247. /* V1.3.2b - if this is our buffer packet - get rid of the buffer */
  4248. if (resp -> type == MAIN_PACKET_TYPE_INDICATE ||
  4249. resp -> type == MAIN_PACKET_TYPE_CTRL)
  4250. {
  4251. /* strip buffers from the packet buffer chain */
  4252. NdisUnchainBufferAtFront (packet, & bufp);
  4253. bp = (PMAIN_BUFFER) resp -> miscp;
  4254. UNIV_ASSERT (bp -> code == MAIN_BUFFER_CODE);
  4255. NdisAcquireSpinLock (& ctxtp -> buf_lock);
  4256. ctxtp -> num_bufs_out--;
  4257. InsertTailList (& ctxtp -> buf_list, & bp -> link);
  4258. NdisReleaseSpinLock (& ctxtp -> buf_lock);
  4259. /* Indicated packets use MiniportReserved, while CTRL packets use ProtocolReserved,
  4260. so indicated packets need to free the resp buffer back to the list. */
  4261. if (resp -> type == MAIN_PACKET_TYPE_INDICATE) {
  4262. resp -> type = MAIN_PACKET_TYPE_NONE;
  4263. NdisFreeToNPagedLookasideList (& ctxtp -> resp_list, resp);
  4264. }
  4265. }
  4266. else
  4267. {
  4268. UNIV_ASSERT_VAL (resp -> type == MAIN_PACKET_TYPE_PASS ||
  4269. resp -> type == MAIN_PACKET_TYPE_TRANSFER,
  4270. resp -> type);
  4271. oldp = (PNDIS_PACKET) resp -> miscp;
  4272. /* If the old packet is the same as this packet, then we were using
  4273. NDIS packet stacking to hold our private data. In this case, we
  4274. ALWAYS need to free the resp buffer back to our list. */
  4275. if (oldp == packet)
  4276. {
  4277. resp -> type = MAIN_PACKET_TYPE_NONE;
  4278. NdisFreeToNPagedLookasideList (& ctxtp -> resp_list, resp);
  4279. return packet;
  4280. }
  4281. #if defined (SBH)
  4282. /* It used to be that if a new packet was allocated, we always used
  4283. protocol reseved, so there was never a need to free our private
  4284. buffer (it was part of the packet itself). However, now in the
  4285. case where packet != oldp (we allocated a new packet) we may have
  4286. to free the private data buffer. If we allocate a packet on the
  4287. send path, we play the part of protocol and use the protocol
  4288. reserved field, which is the former behavior. However, if we
  4289. allocate a packet on the receive path, we pull a resp buffer off
  4290. of our lookaside list and store a pointer in the miniport reserved
  4291. field of the packet. Therefore, if this is the completion of a
  4292. receive, free the private buffer. */
  4293. if (!send)
  4294. NdisFreeToNPagedLookasideList (& ctxtp -> resp_list, resp);
  4295. #endif
  4296. // Copy the per packet info into the new packet
  4297. if (send)
  4298. NdisIMCopySendCompletePerPacketInfo(oldp, packet);
  4299. resp -> type = MAIN_PACKET_TYPE_NONE;
  4300. }
  4301. /* These conters ONLY count outstanding allocated packets - for resource tracking. */
  4302. if (send)
  4303. NdisInterlockedDecrement(& ctxtp -> num_sends_out);
  4304. else
  4305. NdisInterlockedDecrement(& ctxtp -> num_recvs_out);
  4306. NdisReinitializePacket (packet);
  4307. NdisFreePacket (packet);
  4308. return oldp;
  4309. } /* end Main_packet_put */
  4310. #ifdef PERIODIC_RESET
  4311. static ULONG countdown = 0;
  4312. ULONG resetting = FALSE;
  4313. #endif
  4314. VOID Main_ping (
  4315. PMAIN_CTXT ctxtp,
  4316. PULONG toutp)
  4317. {
  4318. ULONG len, conns;
  4319. BOOLEAN alive, converging;
  4320. PNDIS_PACKET packet;
  4321. NDIS_STATUS status;
  4322. BOOLEAN send_heartbeat = TRUE;
  4323. #ifdef PERIODIC_RESET /* enable this to simulate periodic resets */
  4324. if (countdown++ == 15)
  4325. {
  4326. NDIS_STATUS status;
  4327. resetting = TRUE;
  4328. NdisReset (& status, ctxtp -> mac_handle);
  4329. if (status == NDIS_STATUS_SUCCESS)
  4330. resetting = FALSE;
  4331. countdown = 0;
  4332. }
  4333. #endif
  4334. /* If unbind handler has been called, return here */
  4335. if (ctxtp -> unbind_handle)
  4336. return;
  4337. /* The master adapter must check the consistency of its team's configuration
  4338. and appropriately activate/de-activate the team once per timeout. */
  4339. Main_teaming_check_consistency(ctxtp);
  4340. /* count down time left for blocking ARPs */
  4341. NdisAcquireSpinLock (& ctxtp -> load_lock); /* V1.0.3 */
  4342. if (*toutp > univ_changing_ip)
  4343. univ_changing_ip = 0;
  4344. else
  4345. univ_changing_ip -= *toutp;
  4346. alive = Load_timeout (& ctxtp -> load, toutp, & converging, & conns);
  4347. /* moving release to the end of the function locks up one of the testbeds.
  4348. guessing because of some reentrancy problem with NdisSend that is being
  4349. called by ctxtp_frame_send */
  4350. if (! ctxtp -> convoy_enabled && ! ctxtp -> stopping)
  4351. {
  4352. UNIV_ASSERT (! ctxtp -> draining);
  4353. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3 */
  4354. send_heartbeat = FALSE;
  4355. // return;
  4356. }
  4357. /* V2.1 if draining and no more connections - stop cluster mode */
  4358. if (send_heartbeat)
  4359. {
  4360. if (ctxtp -> draining && conns == 0 && ! converging)
  4361. {
  4362. IOCTL_CVY_BUF buf;
  4363. ctxtp -> draining = FALSE;
  4364. NdisReleaseSpinLock (& ctxtp -> load_lock);
  4365. Main_ctrl (ctxtp, (ULONG) IOCTL_CVY_CLUSTER_OFF, & buf, NULL);
  4366. }
  4367. else
  4368. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3 */
  4369. /* V2.1 clear stopping flag here since we are going to send out the frame
  4370. that will initiate convergence */
  4371. ctxtp -> stopping = FALSE;
  4372. }
  4373. /* V1.3.2b */
  4374. if (! ctxtp -> media_connected || ! MAIN_PNP_DEV_ON(ctxtp))
  4375. return;
  4376. /* V1.1.2 do not send pings if the card below is resetting */
  4377. if (ctxtp -> reset_state != MAIN_RESET_NONE)
  4378. return;
  4379. if (send_heartbeat)
  4380. {
  4381. packet = Main_frame_get (ctxtp, TRUE, & len, MAIN_PACKET_TYPE_PING);
  4382. if (packet == NULL)
  4383. {
  4384. UNIV_PRINT (("error getting frame packet"));
  4385. return;
  4386. }
  4387. NdisSend (& status, ctxtp -> mac_handle, packet);
  4388. if (status != NDIS_STATUS_PENDING)
  4389. Main_send_done (ctxtp, packet, status);
  4390. }
  4391. /* Check to see if igmp message needs to be sent out. If the cluster IP address is 0.0.0.0, we
  4392. don't want to join the multicast IGMP group. Likewise, in multicast or unicast mode. */
  4393. if (ctxtp -> params . mcast_support && ctxtp -> params . igmp_support && ctxtp -> params . cl_ip_addr != 0)
  4394. {
  4395. ctxtp -> igmp_sent += ctxtp -> curr_tout;
  4396. if (ctxtp -> igmp_sent < CVY_DEF_IGMP_INTERVAL)
  4397. return;
  4398. ctxtp -> igmp_sent = 0;
  4399. packet = Main_frame_get (ctxtp, TRUE, & len, MAIN_PACKET_TYPE_IGMP);
  4400. if (packet == NULL)
  4401. {
  4402. UNIV_PRINT (("error getting igmp packet"));
  4403. return;
  4404. }
  4405. NdisSend (& status, ctxtp -> mac_handle, packet);
  4406. if (status != NDIS_STATUS_PENDING)
  4407. Main_send_done (ctxtp, packet, status);
  4408. }
  4409. } /* Main_ping */
  4410. VOID Main_send_done (
  4411. PVOID cp,
  4412. PNDIS_PACKET packetp,
  4413. NDIS_STATUS status)
  4414. {
  4415. PMAIN_CTXT ctxtp = (PMAIN_CTXT) cp;
  4416. PMAIN_FRAME_DSCR dscrp;
  4417. /* shouse - This function is only called for ping and IGMP messages, so
  4418. we can continue to allow it to access the protocol reserved field. */
  4419. PMAIN_PROTOCOL_RESERVED resp = MAIN_PROTOCOL_FIELD (packetp);
  4420. UNIV_ASSERT_VAL (resp -> type == MAIN_PACKET_TYPE_PING ||
  4421. resp -> type == MAIN_PACKET_TYPE_IGMP, resp -> type);
  4422. /* attempt to see if this packet is part of our frame descriptor */
  4423. dscrp = (PMAIN_FRAME_DSCR) resp -> miscp;
  4424. if (status != NDIS_STATUS_SUCCESS)
  4425. UNIV_PRINT (("error sending %x error 0x%x", resp -> type, status));
  4426. Main_frame_put (ctxtp, packetp, dscrp);
  4427. } /* end Main_send_done */
  4428. VOID Main_xfer_done (
  4429. PVOID cp,
  4430. PNDIS_PACKET packetp,
  4431. NDIS_STATUS status,
  4432. ULONG xferred)
  4433. {
  4434. PMAIN_CTXT ctxtp = (PMAIN_CTXT) cp;
  4435. PMAIN_FRAME_DSCR dscrp;
  4436. /* shouse - This function is only called for ping messages, so we can
  4437. continue to allow it to access the protocol reserved field. */
  4438. PMAIN_PROTOCOL_RESERVED resp = MAIN_PROTOCOL_FIELD (packetp);
  4439. UNIV_ASSERT_VAL (resp -> type == MAIN_PACKET_TYPE_PING, resp -> type);
  4440. dscrp = (PMAIN_FRAME_DSCR) resp -> miscp;
  4441. if (status != NDIS_STATUS_SUCCESS)
  4442. {
  4443. UNIV_PRINT (("error transferring %x", status));
  4444. }
  4445. else if (xferred != dscrp -> recv_len)
  4446. {
  4447. UNIV_PRINT (("only xferred %d out of %d bytes", xferred, sizeof (MAIN_FRAME_HDR)));
  4448. }
  4449. else
  4450. {
  4451. /* let load deal with received heartbeat */
  4452. NdisAcquireSpinLock (& ctxtp -> load_lock); /* V1.0.3 */
  4453. if (ctxtp -> convoy_enabled) /* V1.3.2b */
  4454. Load_msg_rcv (& ctxtp -> load, & dscrp -> msg); /* V1.1.4 */
  4455. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3 */
  4456. }
  4457. Main_frame_put (ctxtp, packetp, dscrp);
  4458. } /* end Main_xfer_done */
  4459. PUCHAR Main_frame_parse (
  4460. PMAIN_CTXT ctxtp,
  4461. PNDIS_PACKET packetp,
  4462. PUCHAR * startp, /* destination for the MAC header */
  4463. ULONG off, /* offset from beginning of data - 0 means
  4464. right after IP header */
  4465. PUCHAR * locp, /* destination for the TCP/UDP/other header */
  4466. PULONG lenp, /* length without media header */
  4467. PUSHORT sigp, /* signature from the MAC header */
  4468. PUSHORT group, /* directed, multicast or broadcast */
  4469. ULONG send)
  4470. /*
  4471. Parse packet extracting real pointers to specified offsets
  4472. returns PUCHAR:
  4473. <pointer to specified offset>
  4474. */
  4475. {
  4476. PNDIS_BUFFER bufp;
  4477. PUCHAR memp, retp;
  4478. UINT len, total_len;
  4479. ULONG curr_len = 0, hdr_len, offset;
  4480. /* get basic frame info */
  4481. NdisGetFirstBufferFromPacket (packetp, & bufp, & memp, & len, & total_len);
  4482. if (bufp == NULL)
  4483. return NULL;
  4484. // NdisQueryBuffer (bufp, & memp, & len);
  4485. * startp = memp;
  4486. offset = CVY_MAC_DST_OFF (ctxtp -> medium);
  4487. /* V2.0.6 - figure out frame type for stats */
  4488. if (! CVY_MAC_ADDR_MCAST (ctxtp -> medium, memp + offset))
  4489. * group = MAIN_FRAME_DIRECTED;
  4490. else
  4491. {
  4492. if (CVY_MAC_ADDR_BCAST (ctxtp -> medium, memp + offset))
  4493. * group = MAIN_FRAME_BROADCAST;
  4494. else
  4495. * group = MAIN_FRAME_MULTICAST;
  4496. }
  4497. /* V1.3.0b multicast support V1.3.1b - on receive mask the cluster MAC
  4498. so that protocol does not get confused */
  4499. if (ctxtp -> params . mcast_support)
  4500. {
  4501. if (! send &&
  4502. CVY_MAC_ADDR_COMP (ctxtp -> medium, memp + offset, & ctxtp -> cl_mac_addr))
  4503. CVY_MAC_ADDR_COPY (ctxtp -> medium, memp + offset, & ctxtp -> ded_mac_addr);
  4504. }
  4505. /* V2.0.6 source MAC address shadowing to prevent switches from learning */
  4506. else if (send && ctxtp -> params . mask_src_mac)
  4507. {
  4508. offset = CVY_MAC_SRC_OFF (ctxtp -> medium);
  4509. if (CVY_MAC_ADDR_COMP (ctxtp -> medium, memp + offset, & ctxtp -> cl_mac_addr))
  4510. {
  4511. CVY_MAC_ADDR_COPY (ctxtp -> medium, memp + offset, & ctxtp -> ded_mac_addr);
  4512. //
  4513. // Change to the unique mac.
  4514. // Note, this can be done during initialization to improve performance
  4515. //
  4516. CVY_MAC_ADDR_LAA_SET (ctxtp -> medium, memp + offset);
  4517. * ((PUCHAR) (memp + offset + 1)) = (UCHAR) ctxtp -> params . host_priority;
  4518. /* // 64-bit -- ramkrish
  4519. * ((PULONG) (memp + offset + 2)) = ctxtp -> cl_ip_addr;
  4520. */
  4521. // ctxtp -> mac_modified ++;
  4522. }
  4523. }
  4524. /* get header length and signature from the frame depending on the medium */
  4525. if (ctxtp -> medium == NdisMedium802_3)
  4526. {
  4527. hdr_len = sizeof (CVY_ETHERNET_HDR);
  4528. * sigp = CVY_ETHERNET_ETYPE_GET (memp);
  4529. }
  4530. if (total_len < hdr_len)
  4531. {
  4532. return NULL;
  4533. }
  4534. /* get payload length */
  4535. * lenp = total_len - hdr_len;
  4536. /* traverse buffers until we find payload offset and remember the pointer */
  4537. while (1)
  4538. {
  4539. if (curr_len + len > hdr_len)
  4540. {
  4541. retp = memp + (hdr_len - curr_len);
  4542. break;
  4543. }
  4544. curr_len += len;
  4545. NdisGetNextBuffer (bufp, & bufp);
  4546. if (bufp == NULL)
  4547. return NULL;
  4548. NdisQueryBuffer (bufp, & memp, & len);
  4549. }
  4550. /* by default assume next offset is after IP header */
  4551. if (off == 0)
  4552. off = sizeof (ULONG) * IP_GET_HLEN ((PIP_HDR) retp);
  4553. hdr_len += off;
  4554. /* traverse buffers until we find next offset and remember the pointer */
  4555. while (1)
  4556. {
  4557. if (curr_len + len > hdr_len)
  4558. {
  4559. * locp = memp + (hdr_len - curr_len);
  4560. break;
  4561. }
  4562. curr_len += len;
  4563. NdisGetNextBuffer (bufp, & bufp);
  4564. if (bufp == NULL)
  4565. {
  4566. * locp = NULL;
  4567. break;
  4568. }
  4569. NdisQueryBuffer (bufp, & memp, & len);
  4570. }
  4571. return retp;
  4572. } /* end Main_frame_parse */
  4573. PUCHAR Main_frame_find (
  4574. PMAIN_CTXT ctxtp,
  4575. PUCHAR head_buf,
  4576. PUCHAR look_buf,
  4577. UINT look_len,
  4578. PUSHORT sigp)
  4579. {
  4580. /* get payload location and signature from the frame depending on the medium */
  4581. if (ctxtp -> medium == NdisMedium802_3)
  4582. {
  4583. * sigp = CVY_ETHERNET_ETYPE_GET (head_buf);
  4584. return look_buf;
  4585. }
  4586. return look_buf;
  4587. } /* end Main_frame_find */
  4588. NDIS_STATUS Main_dispatch (
  4589. PVOID DeviceObject,
  4590. PVOID Irp)
  4591. {
  4592. PIRP pIrp = Irp;
  4593. PIO_STACK_LOCATION irpStack;
  4594. NDIS_STATUS status = NDIS_STATUS_SUCCESS;
  4595. UNIV_PRINT(("Main_dispatch: Device=%p, Irp=%p \n", DeviceObject, Irp));
  4596. irpStack = IoGetCurrentIrpStackLocation(pIrp);
  4597. switch (irpStack->MajorFunction) {
  4598. case IRP_MJ_DEVICE_CONTROL:
  4599. status = Main_ioctl(DeviceObject, Irp);
  4600. break;
  4601. default:
  4602. break;
  4603. }
  4604. pIrp->IoStatus.Status = status;
  4605. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4606. return status;
  4607. }
  4608. NDIS_STATUS Main_ioctl (
  4609. PVOID device,
  4610. PVOID irp_irp)
  4611. {
  4612. PIRP irp = irp_irp;
  4613. PIO_STACK_LOCATION irp_sp;
  4614. ULONG ilen, olen, info = 0;
  4615. NDIS_STATUS status = NDIS_STATUS_SUCCESS;
  4616. ULONG io_ctrl_code;
  4617. PMAIN_CTXT ctxtp = ioctrl_ctxtp;
  4618. PIOCTL_LOCAL_HDR bufp;
  4619. ULONG adapter_index;
  4620. irp_sp = IoGetCurrentIrpStackLocation (irp);
  4621. io_ctrl_code = irp_sp -> Parameters . DeviceIoControl . IoControlCode;
  4622. ilen = irp_sp -> Parameters . DeviceIoControl . InputBufferLength;
  4623. olen = irp_sp -> Parameters . DeviceIoControl . OutputBufferLength;
  4624. bufp = irp -> AssociatedIrp . SystemBuffer;
  4625. switch (io_ctrl_code)
  4626. {
  4627. case IOCTL_CVY_CLUSTER_ON:
  4628. case IOCTL_CVY_CLUSTER_OFF:
  4629. case IOCTL_CVY_PORT_ON:
  4630. case IOCTL_CVY_PORT_OFF:
  4631. case IOCTL_CVY_QUERY:
  4632. case IOCTL_CVY_RELOAD:
  4633. case IOCTL_CVY_PORT_SET:
  4634. case IOCTL_CVY_PORT_DRAIN:
  4635. case IOCTL_CVY_CLUSTER_DRAIN:
  4636. case IOCTL_CVY_CLUSTER_SUSPEND:
  4637. case IOCTL_CVY_CLUSTER_RESUME:
  4638. /* Picking univ_ctxt_hanlde here is not kosher, since we should
  4639. get the callback cookie out of callb_ctxtp from ctxtp context.
  4640. Since we do not have it - do what we can now - cheat :) */
  4641. if (ilen != sizeof (IOCTL_LOCAL_HDR) || olen != sizeof (IOCTL_LOCAL_HDR) || bufp == NULL)
  4642. {
  4643. UNIV_PRINT(("Buffer is missing or not the expected (%d) size: %d, %d", sizeof(IOCTL_LOCAL_HDR), ilen, olen));
  4644. status = STATUS_INVALID_PARAMETER;
  4645. break;
  4646. }
  4647. adapter_index = Main_adapter_get (bufp -> device_name);
  4648. if (adapter_index == MAIN_ADAPTER_NOT_FOUND)
  4649. {
  4650. UNIV_PRINT(("Unknown adapter: %ls", bufp -> device_name));
  4651. status = STATUS_INVALID_PARAMETER;
  4652. break;
  4653. }
  4654. UNIV_PRINT(("Ioctl %d for adapter %ls", io_ctrl_code, bufp -> device_name));
  4655. ctxtp = univ_adapters [adapter_index] . ctxtp;
  4656. irp -> IoStatus . Information = sizeof (IOCTL_LOCAL_HDR);
  4657. /* Process the IOCTL. All necessary information except the VIP is in the IOCTL_CVY_BUF. For
  4658. backward compatiblilty reasons, we need to store the virtual IP address in the local buffer. */
  4659. status = Main_ctrl (ctxtp, io_ctrl_code, & (bufp -> ctrl), & (bufp -> options));
  4660. break;
  4661. case IOCTL_CVY_QUERY_STATE:
  4662. /* Check the lengths of the input and output buffers specified by the user-space application. */
  4663. if (ilen != sizeof (IOCTL_LOCAL_HDR) || olen != sizeof (IOCTL_LOCAL_HDR) || !bufp) {
  4664. UNIV_PRINT(("Buffer is missing or not the expected (%d) size: input=%d, output=%d", sizeof(IOCTL_LOCAL_HDR), ilen, olen));
  4665. status = STATUS_INVALID_PARAMETER;
  4666. break;
  4667. }
  4668. /* Map from the GUID to the adapter index. */
  4669. if ((adapter_index = Main_adapter_get(bufp->device_name)) == MAIN_ADAPTER_NOT_FOUND) {
  4670. UNIV_PRINT(("Unknown adapter: %ls", bufp->device_name));
  4671. status = STATUS_INVALID_PARAMETER;
  4672. break;
  4673. }
  4674. UNIV_PRINT(("Ioctl for adapter %ls", bufp->device_name));
  4675. /* Fill in the number of bytes written. This IOCTL always writes the same number of bytes that it
  4676. reads. That is, the input and output buffers should be identical structures. */
  4677. irp->IoStatus.Information = sizeof(IOCTL_LOCAL_HDR);
  4678. /* Retrieve the context pointer from the global arrary of adapters. */
  4679. ctxtp = univ_adapters[adapter_index].ctxtp;
  4680. /* Call the query state IOCTL handler. */
  4681. status = Query_state_ctrl(ctxtp, bufp->options.state.flags, &bufp->options.state.query);
  4682. break;
  4683. #if defined (NLB_SESSION_SUPPORT)
  4684. case IOCTL_CVY_CONNECTION_NOTIFY:
  4685. /* Check the lengths of the input and output buffers specified by the user-space application. */
  4686. if (ilen != sizeof (IOCTL_LOCAL_HDR) || olen != sizeof (IOCTL_LOCAL_HDR) || !bufp) {
  4687. UNIV_PRINT(("Buffer is missing or not the expected (%d) size: input=%d, output=%d", sizeof(IOCTL_LOCAL_HDR), ilen, olen));
  4688. status = STATUS_INVALID_PARAMETER;
  4689. break;
  4690. }
  4691. /* Map from the GUID to the adapter index. */
  4692. if ((adapter_index = Main_adapter_get(bufp->device_name)) == MAIN_ADAPTER_NOT_FOUND) {
  4693. UNIV_PRINT(("Unknown adapter: %ls", bufp->device_name));
  4694. status = STATUS_INVALID_PARAMETER;
  4695. break;
  4696. }
  4697. UNIV_PRINT(("Ioctl for adapter %ls", bufp->device_name));
  4698. /* Fill in the number of bytes written. This IOCTL always writes the same number of bytes that it
  4699. reads. That is, the input and output buffers should be identical structures. */
  4700. irp->IoStatus.Information = sizeof(IOCTL_LOCAL_HDR);
  4701. /* Retrieve the context pointer from the global arrary of adapters. */
  4702. ctxtp = univ_adapters[adapter_index].ctxtp;
  4703. /* Call the connection notification IOCTL handler. */
  4704. status = Conn_notify_ctrl(ctxtp, bufp->options.notify.flags, &bufp->options.notify.conn);
  4705. break;
  4706. #endif
  4707. #if defined (SBH)
  4708. case IOCTL_CVY_QUERY_PERF:
  4709. irp -> IoStatus . Information = 0;
  4710. if (ilen != sizeof (IOCTL_LOCAL_HDR) || olen != sizeof (CVY_DRIVER_PERF) || bufp == NULL)
  4711. {
  4712. UNIV_PRINT(("Buffer is missing or not the expected (%d) size: %d, %d", sizeof(IOCTL_LOCAL_HDR), ilen, olen));
  4713. status = STATUS_INVALID_PARAMETER;
  4714. break;
  4715. }
  4716. adapter_index = Main_adapter_get (bufp -> device_name);
  4717. if (adapter_index == MAIN_ADAPTER_NOT_FOUND)
  4718. {
  4719. UNIV_PRINT(("Unknown adapter: %ls", bufp -> device_name));
  4720. status = STATUS_INVALID_PARAMETER;
  4721. break;
  4722. }
  4723. UNIV_PRINT(("Ioctl perf for adapter %ls", bufp -> device_name));
  4724. ctxtp = univ_adapters [adapter_index] . ctxtp;
  4725. status = Main_QueryPerf(ctxtp, (PCVY_DRIVER_PERF)bufp);
  4726. if (status == NDIS_STATUS_SUCCESS)
  4727. {
  4728. irp -> IoStatus . Information = sizeof (CVY_DRIVER_PERF);
  4729. }
  4730. break;
  4731. #endif /* SBH */
  4732. default:
  4733. UNIV_PRINT(("Unknown Ioctl code: %x", io_ctrl_code));
  4734. break;
  4735. }
  4736. return status;
  4737. } /* end Main_ioctl */
  4738. /*
  4739. * Function: Query_state_ctrl
  4740. * Description:
  4741. * Parameters:
  4742. * Returns:
  4743. * Author: shouse 5.18.01
  4744. */
  4745. NDIS_STATUS Query_state_ctrl (PMAIN_CTXT ctxtp, ULONG fOptions, PIOCTL_QUERY_STATE pQuery) {
  4746. PMAIN_ADAPTER pAdapter = &(univ_adapters[ctxtp->adapter_id]);
  4747. NdisAcquireSpinLock(&univ_bind_lock);
  4748. /* If the adapter isn't initialized yet, refuse the request. */
  4749. if (!pAdapter->inited) {
  4750. NdisReleaseSpinLock(&univ_bind_lock);
  4751. pQuery->ReturnCode = NLB_QUERY_STATE_FAILURE;
  4752. return NDIS_STATUS_SUCCESS;
  4753. }
  4754. NdisReleaseSpinLock(&univ_bind_lock);
  4755. switch (pQuery->Operation) {
  4756. case NLB_QUERY_REG_PARAMS:
  4757. case NLB_QUERY_PORT_RULE_STATE:
  4758. case NLB_QUERY_BDA_TEAM_STATE:
  4759. case NLB_QUERY_PACKET_STATISTICS:
  4760. UNIV_PRINT (("Unimplemented operation: %d", pQuery->Operation));
  4761. pQuery->ReturnCode = NLB_QUERY_STATE_FAILURE;
  4762. break;
  4763. /* Given a IP tuple (client IP, client port, server IP, server port) and a protocol,
  4764. determine whether or not this host would accept the packet and why or why not. It
  4765. is important that this is performed completely unobtrusively and has no side-effects
  4766. on the actual operation of NLB and the load module. */
  4767. case NLB_QUERY_PACKET_FILTER:
  4768. /* Being by Zero'ing out the results portion of the buffer. */
  4769. NdisZeroMemory(&pQuery->Filter.Results, sizeof(pQuery->Filter.Results));
  4770. /* Query NLB for packet filter information for this IP tuple and protocol. Main_query_packet_filter
  4771. checks the NDIS driver information for filtering issues such as DIP traffic, BDA teaming and
  4772. NLB driver state (on/off due to wlbs.exe commands and parameter errors). If necessary, it then
  4773. consults the load module to perform the actual port rule lookup and determine packet acceptance. */
  4774. Main_query_packet_filter(ctxtp, &pQuery->Filter);
  4775. /* This should always result in success, whether the packet is accepted or not. */
  4776. pQuery->ReturnCode = NLB_QUERY_STATE_SUCCESS;
  4777. break;
  4778. default:
  4779. UNIV_PRINT (("Unknown operation: %d", pQuery->Operation));
  4780. pQuery->ReturnCode = NLB_QUERY_STATE_FAILURE;
  4781. break;
  4782. }
  4783. return NDIS_STATUS_SUCCESS;
  4784. }
  4785. #if defined (NLB_SESSION_SUPPORT)
  4786. /*
  4787. * Function: Conn_notify_ctrl
  4788. * Description:
  4789. * Parameters:
  4790. * Returns:
  4791. * Author: shouse 4.30.01
  4792. */
  4793. NDIS_STATUS Conn_notify_ctrl (PMAIN_CTXT ctxtp, ULONG fOptions, PIOCTL_CONN_NOTIFICATION pConn) {
  4794. PMAIN_ADAPTER pAdapter = &(univ_adapters[ctxtp->adapter_id]);
  4795. BOOLEAN bRefused = FALSE;
  4796. BOOLEAN bRet = TRUE;
  4797. NdisAcquireSpinLock(&univ_bind_lock);
  4798. /* If the adapter isn't initialized yet, refuse the request. */
  4799. if (!pAdapter->inited) {
  4800. NdisReleaseSpinLock(&univ_bind_lock);
  4801. pConn->ReturnCode = NLB_ERROR_GENERIC_FAILURE;
  4802. return NDIS_STATUS_SUCCESS;
  4803. }
  4804. NdisReleaseSpinLock(&univ_bind_lock);
  4805. /* Make sure that the parameters from the input buffer are valid. */
  4806. if ((pConn->Protocol != TCPIP_PROTOCOL_IPSEC1) || (pConn->ServerPort > CVY_MAX_PORT) ||
  4807. (pConn->ClientPort > CVY_MAX_PORT) || (!pConn->ServerIPAddress) || (!pConn->ClientIPAddress)) {
  4808. /* Use the return code in the IOCTL buffer to relay a parameter error and return success. */
  4809. pConn->ReturnCode = NLB_ERROR_INVALID_PARAMETER;
  4810. return NDIS_STATUS_SUCCESS;
  4811. }
  4812. switch (pConn->Operation) {
  4813. case NLB_CONN_UP:
  4814. /* Notify the load module of the upcoming connection. */
  4815. bRet = Main_create_dscr(ctxtp, pConn->ServerIPAddress, pConn->ServerPort, pConn->ClientIPAddress, pConn->ClientPort, pConn->Protocol, &bRefused, FALSE);
  4816. /* If the packet was refused by BDA or rejected by the load module, return refusal error, otherwise, it succeeded. */
  4817. if (bRefused || !bRet)
  4818. pConn->ReturnCode = NLB_ERROR_REQUEST_REFUSED;
  4819. else
  4820. pConn->ReturnCode = NLB_ERROR_SUCCESS;
  4821. break;
  4822. case NLB_CONN_DOWN:
  4823. case NLB_CONN_RESET:
  4824. /* Notify the load module that a connection is being torn down. */
  4825. bRet = Main_conn_advise(ctxtp, pConn->ServerIPAddress, pConn->ServerPort, pConn->ClientIPAddress, pConn->ClientPort, pConn->Protocol, CVY_CONN_DOWN, &bRefused, FALSE);
  4826. /* If the packet was refused by BDA or rejected by the load module, return refusal error, otherwise, it succeeded. */
  4827. if (bRefused || !bRet)
  4828. pConn->ReturnCode = NLB_ERROR_REQUEST_REFUSED;
  4829. else
  4830. pConn->ReturnCode = NLB_ERROR_SUCCESS;
  4831. break;
  4832. default:
  4833. UNIV_PRINT (("Unknown operation: %d", pConn->Operation));
  4834. /* This should never, ever happen, but if it does, signal a generic NLB error and fail. */
  4835. pConn->ReturnCode = NLB_ERROR_GENERIC_FAILURE;
  4836. break;
  4837. }
  4838. return NDIS_STATUS_SUCCESS;
  4839. }
  4840. #endif
  4841. NDIS_STATUS Main_ctrl (
  4842. PMAIN_CTXT ctxtp,
  4843. ULONG io_ctrl_code,
  4844. PIOCTL_CVY_BUF bufp,
  4845. /* Note: optionsp CAN be NULL, so you must check it first. */
  4846. PIOCTL_OPTIONS optionsp)
  4847. {
  4848. WCHAR num [20];
  4849. ULONG mode;
  4850. ULONG old_ip;
  4851. PMAIN_ADAPTER adapterp = & (univ_adapters [ctxtp -> adapter_id]);
  4852. NdisAcquireSpinLock(& univ_bind_lock);
  4853. if (! adapterp -> inited)
  4854. {
  4855. NdisReleaseSpinLock(& univ_bind_lock);
  4856. UNIV_PRINT (("unbound from all NICs"));
  4857. return NDIS_STATUS_FAILURE;
  4858. }
  4859. NdisReleaseSpinLock(& univ_bind_lock);
  4860. /* make sure data is written into bufp AFTER taking everything we need
  4861. out of it !!! */
  4862. switch (io_ctrl_code)
  4863. {
  4864. case IOCTL_CVY_RELOAD:
  4865. {
  4866. CVY_PARAMS old_params;
  4867. CVY_PARAMS new_params;
  4868. if (KeGetCurrentIrql () > PASSIVE_LEVEL)
  4869. {
  4870. UNIV_PRINT (("!!! IRQL IS TOO HIGH %d\n", KeGetCurrentIrql ()));
  4871. return NDIS_STATUS_FAILURE;
  4872. }
  4873. /* Take a snapshot of the old parameter set for later comparison. */
  4874. RtlCopyMemory(&old_params, &ctxtp -> params, sizeof(ctxtp -> params));
  4875. /* Spin locks can not be acquired when we are calling Params_init
  4876. since it will be doing registry access operations that depend on
  4877. running at PASSIVEL_IRQL_LEVEL. Therefore, we gather the new
  4878. parameters into a temporary structure and copy them in the NLB
  4879. context protected by a spin lock. */
  4880. if (Params_init(ctxtp, univ_reg_path, adapterp->device_name + 8, &new_params) != NDIS_STATUS_SUCCESS)
  4881. {
  4882. UNIV_PRINT (("error retrieving registry parameters"));
  4883. bufp->ret_code = IOCTL_CVY_BAD_PARAMS;
  4884. break;
  4885. }
  4886. NdisAcquireSpinLock (& ctxtp -> load_lock); /* V1.0.3, V1.3.2b */
  4887. /* At this point, we have verified that the new parameters are valid,
  4888. so copy them into the permanent parameters structure. */
  4889. RtlCopyMemory(&ctxtp->params, &new_params, sizeof(ctxtp->params));
  4890. ctxtp->params_valid = TRUE;
  4891. Univ_ulong_to_str (ctxtp -> params . host_priority, num, 10);
  4892. if (ctxtp -> convoy_enabled &&
  4893. Main_ApplyChangeWithoutReStart(ctxtp, &old_params, &ctxtp -> params))
  4894. {
  4895. //
  4896. // Changes is applied with no need to restart
  4897. //
  4898. NdisReleaseSpinLock (& ctxtp -> load_lock);
  4899. bufp -> ret_code = IOCTL_CVY_OK;
  4900. break;
  4901. }
  4902. mode = ctxtp -> convoy_enabled;
  4903. bufp -> ret_code = IOCTL_CVY_OK;
  4904. if (ctxtp -> convoy_enabled)
  4905. {
  4906. ctxtp -> convoy_enabled = FALSE;
  4907. Load_stop (& ctxtp -> load);
  4908. if (ctxtp -> draining)
  4909. {
  4910. ctxtp -> draining = FALSE;
  4911. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3 */
  4912. UNIV_PRINT (("connection draining interrupted"));
  4913. LOG_MSG (MSG_INFO_DRAINING_STOPPED, MSG_NONE);
  4914. bufp -> ret_code = IOCTL_CVY_DRAINING_STOPPED;
  4915. }
  4916. else
  4917. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3 */
  4918. UNIV_PRINT (("cluster mode stopped"));
  4919. LOG_MSG (MSG_INFO_STOPPED, MSG_NONE);
  4920. }
  4921. else
  4922. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3 */
  4923. old_ip = ctxtp->cl_ip_addr;
  4924. if (! Main_ip_addr_init (ctxtp) || ! Main_mac_addr_init (ctxtp) || ! Main_teaming_init(ctxtp))
  4925. {
  4926. ctxtp -> params_valid = FALSE;
  4927. UNIV_PRINT (("parameter error"));
  4928. LOG_MSG (MSG_ERROR_DISABLED, MSG_NONE);
  4929. bufp -> ret_code = IOCTL_CVY_BAD_PARAMS;
  4930. break;
  4931. }
  4932. if (ctxtp -> params . mcast_support && ctxtp -> params . igmp_support)
  4933. Main_igmp_init (ctxtp, TRUE);
  4934. if (old_ip != ctxtp->cl_ip_addr)
  4935. {
  4936. NdisAcquireSpinLock (& ctxtp -> load_lock);
  4937. univ_changing_ip = ctxtp -> params.ip_chg_delay;
  4938. NdisReleaseSpinLock (& ctxtp -> load_lock);
  4939. UNIV_PRINT (("changing IP address with delay %d", univ_changing_ip));
  4940. }
  4941. LOG_MSG (MSG_INFO_RELOADED, MSG_NONE);
  4942. if (mode)
  4943. {
  4944. NdisAcquireSpinLock (& ctxtp -> load_lock); /* V1.0.3, V1.3.2b */
  4945. Load_start (& ctxtp -> load);
  4946. ctxtp -> convoy_enabled = TRUE;
  4947. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3, V1.3.2b */
  4948. UNIV_PRINT (("cluster mode started"));
  4949. LOG_MSG (MSG_INFO_STARTED, num);
  4950. }
  4951. ctxtp -> bad_host_warned = FALSE;
  4952. UNIV_PRINT (("parameters reloaded"));
  4953. break;
  4954. }
  4955. case IOCTL_CVY_CLUSTER_RESUME:
  4956. NdisAcquireSpinLock (& ctxtp -> load_lock); /* V1.0.3, V1.3.2b */
  4957. if (! ctxtp -> suspended)
  4958. {
  4959. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3, V1.3.2b */
  4960. UNIV_PRINT (("cluster mode already resumed"));
  4961. bufp -> ret_code = IOCTL_CVY_ALREADY;
  4962. break;
  4963. }
  4964. UNIV_ASSERT (! ctxtp -> convoy_enabled);
  4965. UNIV_ASSERT (! ctxtp -> draining);
  4966. ctxtp -> suspended = FALSE;
  4967. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3, V1.3.2b */
  4968. UNIV_PRINT (("cluster mode resumed"));
  4969. LOG_MSG (MSG_INFO_RESUMED, MSG_NONE);
  4970. bufp -> ret_code = IOCTL_CVY_OK;
  4971. break;
  4972. case IOCTL_CVY_CLUSTER_ON:
  4973. Univ_ulong_to_str (ctxtp -> params . host_priority, num, 10);
  4974. NdisAcquireSpinLock (& ctxtp -> load_lock); /* V1.0.3, V1.3.2b */
  4975. if (ctxtp -> suspended)
  4976. {
  4977. UNIV_ASSERT (! ctxtp -> convoy_enabled);
  4978. UNIV_ASSERT (! ctxtp -> draining);
  4979. NdisReleaseSpinLock (& ctxtp -> load_lock);
  4980. UNIV_PRINT (("cluster mode is suspended"));
  4981. bufp -> ret_code = IOCTL_CVY_SUSPENDED;
  4982. break;
  4983. }
  4984. /* V2.1 */
  4985. if (ctxtp -> draining)
  4986. {
  4987. UNIV_ASSERT (ctxtp -> convoy_enabled);
  4988. UNIV_PRINT(("START: Calling Load_port_change -> VIP=%08x, port=%d, load=%d\n",
  4989. IOCTL_ALL_VIPS, IOCTL_ALL_PORTS, 0));
  4990. bufp -> ret_code = Load_port_change (& ctxtp -> load,
  4991. IOCTL_ALL_VIPS,
  4992. IOCTL_ALL_PORTS,
  4993. (ULONG) IOCTL_CVY_CLUSTER_PLUG,
  4994. 0);
  4995. ctxtp -> draining = FALSE;
  4996. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3, V1.3.2b */
  4997. UNIV_PRINT (("connection draining interrupted"));
  4998. LOG_MSG (MSG_INFO_DRAINING_STOPPED, MSG_NONE);
  4999. UNIV_PRINT (("cluster mode started"));
  5000. LOG_MSG (MSG_INFO_STARTED, num);
  5001. bufp -> ret_code = IOCTL_CVY_DRAINING_STOPPED;
  5002. break;
  5003. }
  5004. if (ctxtp -> convoy_enabled)
  5005. {
  5006. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3, V1.3.2b */
  5007. UNIV_PRINT (("cluster mode already started"));
  5008. bufp -> ret_code = IOCTL_CVY_ALREADY;
  5009. break;
  5010. }
  5011. if (! ctxtp -> params_valid)
  5012. {
  5013. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3, V1.3.2b */
  5014. UNIV_PRINT (("parameter error"));
  5015. LOG_MSG (MSG_ERROR_DISABLED, MSG_NONE);
  5016. bufp -> ret_code = IOCTL_CVY_BAD_PARAMS;
  5017. break;
  5018. }
  5019. Load_start (& ctxtp -> load);
  5020. ctxtp -> convoy_enabled = TRUE;
  5021. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3, V1.3.2b */
  5022. ctxtp -> bad_host_warned = FALSE;
  5023. UNIV_PRINT (("cluster mode started"));
  5024. LOG_MSG (MSG_INFO_STARTED, num);
  5025. bufp -> ret_code = IOCTL_CVY_OK;
  5026. break;
  5027. case IOCTL_CVY_CLUSTER_SUSPEND:
  5028. NdisAcquireSpinLock (& ctxtp -> load_lock); /* V1.0.3, V1.3.2b */
  5029. if (ctxtp -> suspended)
  5030. {
  5031. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3, V1.3.2b */
  5032. UNIV_PRINT (("cluster mode already suspended"));
  5033. bufp -> ret_code = IOCTL_CVY_ALREADY;
  5034. break;
  5035. }
  5036. ctxtp -> suspended = TRUE;
  5037. if (ctxtp -> convoy_enabled)
  5038. {
  5039. ctxtp -> convoy_enabled = FALSE;
  5040. ctxtp -> stopping = TRUE;
  5041. Load_stop (& ctxtp -> load);
  5042. /* V2.1 */
  5043. if (ctxtp -> draining)
  5044. {
  5045. ctxtp -> draining = FALSE;
  5046. NdisReleaseSpinLock (& ctxtp -> load_lock);
  5047. UNIV_PRINT (("connection draining interrupted"));
  5048. LOG_MSG (MSG_INFO_DRAINING_STOPPED, MSG_NONE);
  5049. bufp -> ret_code = IOCTL_CVY_DRAINING_STOPPED;
  5050. }
  5051. else
  5052. {
  5053. NdisReleaseSpinLock (& ctxtp -> load_lock);
  5054. bufp -> ret_code = IOCTL_CVY_STOPPED;
  5055. }
  5056. UNIV_PRINT (("cluster mode stopped"));
  5057. LOG_MSG (MSG_INFO_STOPPED, MSG_NONE);
  5058. }
  5059. else
  5060. {
  5061. NdisReleaseSpinLock (& ctxtp -> load_lock);
  5062. bufp -> ret_code = IOCTL_CVY_OK;
  5063. }
  5064. UNIV_PRINT (("cluster mode suspended"));
  5065. LOG_MSG (MSG_INFO_SUSPENDED, MSG_NONE);
  5066. break;
  5067. case IOCTL_CVY_CLUSTER_OFF:
  5068. NdisAcquireSpinLock (& ctxtp -> load_lock); /* V1.0.3, V1.3.2b */
  5069. if (ctxtp -> suspended)
  5070. {
  5071. UNIV_ASSERT (! ctxtp -> convoy_enabled);
  5072. UNIV_ASSERT (! ctxtp -> draining);
  5073. NdisReleaseSpinLock (& ctxtp -> load_lock);
  5074. UNIV_PRINT (("cluster mode is suspended"));
  5075. bufp -> ret_code = IOCTL_CVY_SUSPENDED;
  5076. break;
  5077. }
  5078. if (! ctxtp -> convoy_enabled)
  5079. {
  5080. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3, V1.3.2b */
  5081. UNIV_PRINT (("cluster mode already stopped"));
  5082. bufp -> ret_code = IOCTL_CVY_ALREADY;
  5083. break;
  5084. }
  5085. ctxtp -> convoy_enabled = FALSE;
  5086. ctxtp -> stopping = TRUE;
  5087. Load_stop (& ctxtp -> load);
  5088. /* V2.1 */
  5089. if (ctxtp -> draining)
  5090. {
  5091. ctxtp -> draining = FALSE;
  5092. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3 */
  5093. UNIV_PRINT (("connection draining interrupted"));
  5094. LOG_MSG (MSG_INFO_DRAINING_STOPPED, MSG_NONE);
  5095. bufp -> ret_code = IOCTL_CVY_DRAINING_STOPPED;
  5096. }
  5097. else
  5098. {
  5099. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3 */
  5100. bufp -> ret_code = IOCTL_CVY_OK;
  5101. }
  5102. UNIV_PRINT (("cluster mode stopped"));
  5103. LOG_MSG (MSG_INFO_STOPPED, MSG_NONE);
  5104. break;
  5105. /* V2.1 */
  5106. case IOCTL_CVY_CLUSTER_DRAIN:
  5107. NdisAcquireSpinLock (& ctxtp -> load_lock); /* V1.0.3 */
  5108. if (ctxtp -> suspended)
  5109. {
  5110. UNIV_ASSERT (! ctxtp -> convoy_enabled);
  5111. UNIV_ASSERT (! ctxtp -> draining);
  5112. NdisReleaseSpinLock (& ctxtp -> load_lock);
  5113. UNIV_PRINT (("cluster mode is suspended"));
  5114. bufp -> ret_code = IOCTL_CVY_SUSPENDED;
  5115. break;
  5116. }
  5117. if (! ctxtp -> convoy_enabled)
  5118. {
  5119. UNIV_ASSERT (! ctxtp -> draining);
  5120. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3 */
  5121. UNIV_PRINT (("cannot drain connections while cluster is stopped"));
  5122. bufp -> ret_code = IOCTL_CVY_STOPPED;
  5123. break;
  5124. }
  5125. if (ctxtp -> draining)
  5126. {
  5127. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3, V1.3.2b */
  5128. UNIV_PRINT (("already draining"));
  5129. bufp -> ret_code = IOCTL_CVY_ALREADY;
  5130. break;
  5131. }
  5132. ctxtp -> draining = TRUE;
  5133. UNIV_PRINT(("DRAIN: Calling Load_port_change -> VIP=%08x, port=%d, load=%d\n",
  5134. IOCTL_ALL_VIPS, IOCTL_ALL_PORTS, 0));
  5135. bufp -> ret_code = Load_port_change (& ctxtp -> load,
  5136. IOCTL_ALL_VIPS,
  5137. IOCTL_ALL_PORTS,
  5138. io_ctrl_code,
  5139. 0);
  5140. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3 */
  5141. if (bufp -> ret_code == IOCTL_CVY_OK)
  5142. {
  5143. UNIV_PRINT (("connection draining started"));
  5144. LOG_MSG (MSG_INFO_CLUSTER_DRAINED, MSG_NONE);
  5145. }
  5146. break;
  5147. case IOCTL_CVY_PORT_ON:
  5148. case IOCTL_CVY_PORT_SET:
  5149. Univ_ulong_to_str (bufp -> data . port . num, num, 10);
  5150. NdisAcquireSpinLock (& ctxtp -> load_lock); /* V1.0.3 */
  5151. if (ctxtp -> suspended)
  5152. {
  5153. UNIV_ASSERT (! ctxtp -> convoy_enabled);
  5154. UNIV_ASSERT (! ctxtp -> draining);
  5155. NdisReleaseSpinLock (& ctxtp -> load_lock);
  5156. UNIV_PRINT (("cluster mode is suspended"));
  5157. bufp -> ret_code = IOCTL_CVY_SUSPENDED;
  5158. break;
  5159. }
  5160. if (! ctxtp -> convoy_enabled)
  5161. {
  5162. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3 */
  5163. UNIV_PRINT (("cannot enable/disable port while cluster is stopped"));
  5164. LOG_MSG (MSG_WARN_CLUSTER_STOPPED, MSG_NONE);
  5165. bufp -> ret_code = IOCTL_CVY_STOPPED;
  5166. break;
  5167. }
  5168. UNIV_PRINT(("ENABLE: Calling Load_port_change -> VIP=%08x, port=%d, load=%d\n",
  5169. (optionsp) ? optionsp->port.virtual_ip_addr : IOCTL_ALL_VIPS, bufp->data.port.num, bufp->data.port.load));
  5170. bufp -> ret_code = Load_port_change (& ctxtp -> load,
  5171. (optionsp) ? optionsp->port.virtual_ip_addr : IOCTL_ALL_VIPS,
  5172. bufp->data.port.num,
  5173. io_ctrl_code,
  5174. bufp->data.port.load);
  5175. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3 */
  5176. if (bufp -> ret_code == IOCTL_CVY_NOT_FOUND)
  5177. {
  5178. UNIV_PRINT (("port %d not found in any of the valid port rules", bufp -> data . port . num));
  5179. LOG_MSG (MSG_WARN_PORT_NOT_FOUND, num);
  5180. }
  5181. else if (bufp -> ret_code == IOCTL_CVY_OK)
  5182. {
  5183. if (io_ctrl_code == IOCTL_CVY_PORT_ON)
  5184. {
  5185. if (bufp -> data . port . num == IOCTL_ALL_PORTS)
  5186. {
  5187. UNIV_PRINT (("all port rules enabled"));
  5188. LOG_MSG (MSG_INFO_PORT_ENABLED_ALL, MSG_NONE);
  5189. }
  5190. else
  5191. {
  5192. UNIV_PRINT (("rule for port %d enabled", bufp -> data . port . num));
  5193. LOG_MSG (MSG_INFO_PORT_ENABLED, num);
  5194. }
  5195. }
  5196. else
  5197. {
  5198. if (bufp -> data . port . num == IOCTL_ALL_PORTS)
  5199. {
  5200. UNIV_PRINT (("all port rules adjusted"));
  5201. LOG_MSG (MSG_INFO_PORT_ADJUSTED_ALL, MSG_NONE);
  5202. }
  5203. else
  5204. {
  5205. UNIV_PRINT (("rule for port %d adjusted to %d", bufp -> data . port . num, bufp -> data . port . load));
  5206. LOG_MSG (MSG_INFO_PORT_ADJUSTED, num);
  5207. }
  5208. }
  5209. }
  5210. else
  5211. {
  5212. UNIV_PRINT (("port %d already enabled", bufp -> data . port . num));
  5213. }
  5214. break;
  5215. case IOCTL_CVY_PORT_OFF:
  5216. case IOCTL_CVY_PORT_DRAIN:
  5217. Univ_ulong_to_str (bufp -> data . port . num, num, 10);
  5218. NdisAcquireSpinLock (& ctxtp -> load_lock); /* V1.0.3 */
  5219. if (ctxtp -> suspended)
  5220. {
  5221. UNIV_ASSERT (! ctxtp -> convoy_enabled);
  5222. UNIV_ASSERT (! ctxtp -> draining);
  5223. NdisReleaseSpinLock (& ctxtp -> load_lock);
  5224. UNIV_PRINT (("cluster mode is suspended"));
  5225. bufp -> ret_code = IOCTL_CVY_SUSPENDED;
  5226. break;
  5227. }
  5228. if (! ctxtp -> convoy_enabled)
  5229. {
  5230. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3 */
  5231. UNIV_PRINT (("cannot enable/disable port while cluster is stopped"));
  5232. LOG_MSG (MSG_WARN_CLUSTER_STOPPED, MSG_NONE);
  5233. bufp -> ret_code = IOCTL_CVY_STOPPED;
  5234. break;
  5235. }
  5236. UNIV_PRINT(("DISABLE: Calling Load_port_change -> VIP=%08x, port=%d, load=%d\n",
  5237. (optionsp) ? optionsp->port.virtual_ip_addr : IOCTL_ALL_VIPS, bufp->data.port.num, bufp->data.port.load));
  5238. bufp -> ret_code = Load_port_change (& ctxtp -> load,
  5239. (optionsp) ? optionsp->port.virtual_ip_addr : IOCTL_ALL_VIPS,
  5240. bufp->data.port.num,
  5241. io_ctrl_code,
  5242. bufp->data.port.load);
  5243. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3 */
  5244. if (bufp -> ret_code == IOCTL_CVY_NOT_FOUND)
  5245. {
  5246. UNIV_PRINT (("port %d not found in any of the valid port rules", bufp -> data . port . num));
  5247. LOG_MSG (MSG_WARN_PORT_NOT_FOUND, num);
  5248. }
  5249. else if (bufp -> ret_code == IOCTL_CVY_OK)
  5250. {
  5251. if (io_ctrl_code == IOCTL_CVY_PORT_OFF)
  5252. {
  5253. if (bufp -> data . port . num == IOCTL_ALL_PORTS)
  5254. {
  5255. UNIV_PRINT (("all port rules disabled"));
  5256. LOG_MSG (MSG_INFO_PORT_DISABLED_ALL, MSG_NONE);
  5257. }
  5258. else
  5259. {
  5260. UNIV_PRINT (("rule for port %d disabled", bufp -> data . port . num));
  5261. LOG_MSG (MSG_INFO_PORT_DISABLED, num);
  5262. }
  5263. }
  5264. else
  5265. {
  5266. if (bufp -> data . port . num == IOCTL_ALL_PORTS)
  5267. {
  5268. UNIV_PRINT (("all port rules drained"));
  5269. LOG_MSG (MSG_INFO_PORT_DRAINED_ALL, MSG_NONE);
  5270. }
  5271. else
  5272. {
  5273. UNIV_PRINT (("rule for port %d drained", bufp -> data . port . num));
  5274. LOG_MSG (MSG_INFO_PORT_DRAINED, num);
  5275. }
  5276. }
  5277. }
  5278. else
  5279. {
  5280. UNIV_PRINT (("port %d already disabled", bufp -> data . port . num));
  5281. }
  5282. break;
  5283. case IOCTL_CVY_QUERY:
  5284. NdisAcquireSpinLock (& ctxtp -> load_lock); /* V1.0.3 */
  5285. if (ctxtp -> suspended)
  5286. {
  5287. UNIV_PRINT (("cannot query status - this host is suspended"));
  5288. bufp -> data . query . state = IOCTL_CVY_SUSPENDED;
  5289. }
  5290. else if (! ctxtp -> convoy_enabled)
  5291. {
  5292. UNIV_PRINT (("cannot query status - this host is not part of the cluster"));
  5293. bufp -> data . query . state = IOCTL_CVY_STOPPED;
  5294. }
  5295. else if (!ctxtp -> media_connected || !MAIN_PNP_DEV_ON(ctxtp))
  5296. {
  5297. UNIV_PRINT (("cannot query status - this host is not connected to the network"));
  5298. bufp -> data . query . state = IOCTL_CVY_DISCONNECTED;
  5299. }
  5300. else
  5301. {
  5302. ULONG tmp_host_map; /* 64-bit -- ramkrish */
  5303. bufp -> data . query . state = (USHORT) Load_hosts_query (& ctxtp -> load, FALSE,
  5304. & tmp_host_map);
  5305. bufp -> data . query . host_map = tmp_host_map;
  5306. /* V2.1 */
  5307. if (ctxtp -> draining &&
  5308. bufp -> data . query . state != IOCTL_CVY_CONVERGING)
  5309. bufp -> data . query . state = IOCTL_CVY_DRAINING;
  5310. }
  5311. bufp -> data . query . host_id = (USHORT) ctxtp -> params . host_priority;
  5312. NdisReleaseSpinLock (& ctxtp -> load_lock); /* V1.0.3 */
  5313. /* If the user-level application has requested the hostname, return it. */
  5314. if (optionsp && (optionsp->query.flags & IOCTL_OPTIONS_QUERY_HOSTNAME))
  5315. NdisMoveMemory(optionsp->query.hostname, ctxtp->params.hostname, CVY_MAX_HOST_NAME + 1);
  5316. break;
  5317. default:
  5318. UNIV_PRINT (("bad IOCTL %x", io_ctrl_code));
  5319. return NDIS_STATUS_FAILURE;
  5320. }
  5321. return NDIS_STATUS_SUCCESS;
  5322. } /* end Main_ctrl */
  5323. //+----------------------------------------------------------------------------
  5324. //
  5325. // Function: Main_ctrl_recv
  5326. //
  5327. // Description: Process remote control request packet
  5328. //
  5329. // Arguments: MAIN_CTXT ctxtp -
  5330. // PNDIS_PACKET packet -
  5331. //
  5332. // Returns: Nothing
  5333. //
  5334. // History: kyrilf initial code
  5335. // fengsun Created Header 11/15/00
  5336. //
  5337. //+----------------------------------------------------------------------------
  5338. VOID Main_ctrl_recv (
  5339. PMAIN_CTXT ctxtp,
  5340. PNDIS_PACKET packet)
  5341. {
  5342. NDIS_STATUS status = NDIS_STATUS_SUCCESS;
  5343. PIP_HDR ip_hdrp;
  5344. PUCHAR mac_hdrp;
  5345. PUDP_HDR udp_hdrp;
  5346. ULONG len;
  5347. USHORT sig;
  5348. ULONG soff, doff;
  5349. CVY_MAC_ADR tmp_mac;
  5350. PIOCTL_REMOTE_HDR rct_hdrp;
  5351. ULONG state, host_map;
  5352. USHORT checksum, group;
  5353. ULONG i;
  5354. ULONG tmp_src_addr, tmp_dst_addr; /* 64-bit -- ramkrish */
  5355. USHORT tmp_src_port, tmp_dst_port; /* 64-bit -- ramkrish */
  5356. BOOLEAN IgnorePassword = FALSE; // whether to ignore remote control password
  5357. UNIV_PRINT (("Main_ctrl_recv: processing"));
  5358. ip_hdrp = (PIP_HDR) Main_frame_parse (ctxtp, packet, & mac_hdrp, 0,
  5359. (PUCHAR *) & udp_hdrp, & len, & sig,
  5360. & group, FALSE);
  5361. if (ip_hdrp == NULL || udp_hdrp == NULL) /* v2.0.6 */
  5362. goto quit;
  5363. /* v2.0.6 */
  5364. if (len < NLB_MIN_RCTL_PACKET_LEN(ip_hdrp))
  5365. {
  5366. UNIV_PRINT(("remote control packet not expected length: got %d bytes, expected at least %d bytes\n", len, NLB_MIN_RCTL_PACKET_LEN(ip_hdrp)));
  5367. goto quit;
  5368. }
  5369. checksum = Tcpip_chksum (& ctxtp -> tcpip, ip_hdrp, NULL, TCPIP_PROTOCOL_IP);
  5370. if (IP_GET_CHKSUM (ip_hdrp) != checksum)
  5371. {
  5372. UNIV_PRINT (("bad PP checksum %x vs %x\n", IP_GET_CHKSUM (ip_hdrp), checksum))
  5373. goto quit;
  5374. }
  5375. checksum = Tcpip_chksum (& ctxtp -> tcpip, ip_hdrp, (PUCHAR) udp_hdrp, TCPIP_PROTOCOL_UDP);
  5376. if (UDP_GET_CHKSUM (udp_hdrp) != checksum)
  5377. {
  5378. UNIV_PRINT (("bad UDP checksum %x vs %x\n", UDP_GET_CHKSUM (udp_hdrp), checksum))
  5379. goto quit;
  5380. }
  5381. rct_hdrp = (PIOCTL_REMOTE_HDR) UDP_GET_DGRAM_PTR (udp_hdrp);
  5382. /* double-check the code */
  5383. if (rct_hdrp -> code != IOCTL_REMOTE_CODE)
  5384. {
  5385. UNIV_PRINT (("bad RCT code %x\n", rct_hdrp -> code));
  5386. goto quit;
  5387. }
  5388. /* might want to take appropriate actions for a message from a host
  5389. running different version number of software */
  5390. if (rct_hdrp -> version != CVY_VERSION_FULL)
  5391. {
  5392. UNIV_PRINT (("version mismatch %x vs %x", rct_hdrp -> version, CVY_VERSION_FULL));
  5393. }
  5394. /* see if this message is destined for this cluster */
  5395. if (rct_hdrp -> cluster != ctxtp -> cl_ip_addr)
  5396. {
  5397. UNIV_PRINT (("message for cluster %08X rejected on cluster %08X", rct_hdrp -> cluster, ctxtp -> cl_ip_addr));
  5398. goto quit;
  5399. }
  5400. /* 64-bit -- ramkrish */
  5401. tmp_src_addr = IP_GET_SRC_ADDR_64(ip_hdrp);
  5402. tmp_dst_addr = IP_GET_DST_ADDR_64(ip_hdrp);
  5403. /* do not trust src addr in header, since winsock does not resolve
  5404. multihomed addresses properly */
  5405. rct_hdrp -> addr = tmp_src_addr;
  5406. /* If remote control is disabled, we drop the requests. */
  5407. if (!ctxtp->params.rct_enabled) {
  5408. /* If remote control is disabled, still allows query originated from a machine in
  5409. the same cluster. This way, an application running on one host can get a list
  5410. of all hosts (include stopped host) even if remote control is disabled. */
  5411. if (rct_hdrp->ioctrl != IOCTL_CVY_QUERY)
  5412. goto quit;
  5413. /* This in only supported using the XP remote control packet format. */
  5414. if (rct_hdrp->version != CVY_VERSION_FULL)
  5415. goto quit;
  5416. /* Make sure that the packet length is what we expect, or we may fault. */
  5417. if (len < NLB_WINXP_RCTL_PACKET_LEN(ip_hdrp))
  5418. goto quit;
  5419. /* Check to see if the request originated on a member of the cluster for
  5420. which the query is destined. The user-level software on the initiator
  5421. checks its own NLB configuration and sets this bit if it is a member
  5422. of the target cluster. */
  5423. if (!(rct_hdrp->options.query.flags & IOCTL_OPTIONS_QUERY_CLUSTER_MEMBER))
  5424. goto quit;
  5425. /* Ignore the password in such an instance. */
  5426. IgnorePassword = TRUE;
  5427. }
  5428. /* query load to see if we are the master, etc. */
  5429. if (! ctxtp -> convoy_enabled)
  5430. state = IOCTL_CVY_STOPPED;
  5431. else
  5432. state = Load_hosts_query (& ctxtp -> load, FALSE, & host_map);
  5433. /* check if this message is destined to us */
  5434. //
  5435. // The host id in the remote control packet could be
  5436. // IOCTL_MASTER_HOST (0) for master host
  5437. // IOCTL_ALL_HOSTS (FFFFFFFF) for all hosts
  5438. // Host ID, for one host
  5439. // Dedicated IP, for one host
  5440. // Cluster IP, for all hosts in the cluster
  5441. //
  5442. if (rct_hdrp -> host == IOCTL_MASTER_HOST)
  5443. {
  5444. if (state != IOCTL_CVY_MASTER)
  5445. {
  5446. UNIV_PRINT (("RCT request for MASTER host rejected"));
  5447. goto quit;
  5448. }
  5449. }
  5450. else if (rct_hdrp -> host != IOCTL_ALL_HOSTS)
  5451. {
  5452. if (rct_hdrp -> host > CVY_MAX_HOSTS)
  5453. {
  5454. if (! ((ctxtp -> ded_ip_addr != 0 &&
  5455. rct_hdrp -> host == ctxtp -> ded_ip_addr) ||
  5456. rct_hdrp -> host == ctxtp -> cl_ip_addr))
  5457. {
  5458. UNIV_PRINT (("RCT request for host IP %x rejected", rct_hdrp -> host));
  5459. goto quit;
  5460. }
  5461. }
  5462. else
  5463. {
  5464. if (! (rct_hdrp -> host == ctxtp -> params . host_priority ||
  5465. rct_hdrp -> host == 0))
  5466. {
  5467. UNIV_PRINT (("RCT request for host ID %d rejected", rct_hdrp -> host));
  5468. goto quit;
  5469. }
  5470. }
  5471. }
  5472. /* if this is VR remote maintenance password */
  5473. if (rct_hdrp -> password == IOCTL_REMOTE_VR_CODE)
  5474. {
  5475. /* if user disabled this function - drop the packet */
  5476. if (ctxtp -> params . rmt_password == 0)
  5477. {
  5478. UNIV_PRINT (("VR remote password rejected"));
  5479. goto quit;
  5480. }
  5481. else
  5482. {
  5483. UNIV_PRINT (("VR remote password accepted"));
  5484. }
  5485. }
  5486. //
  5487. // This is a new remote control request, with a different source IP
  5488. // or newer ID.
  5489. // Log an event if the password does not match or if the command is not query
  5490. //
  5491. if (! (rct_hdrp -> addr == ctxtp -> rct_last_addr &&
  5492. rct_hdrp -> id <= ctxtp -> rct_last_id))
  5493. {
  5494. WCHAR buf [256];
  5495. PWCHAR ptr = buf;
  5496. //
  5497. // Generate string "SourceIp:SourcePort"
  5498. //
  5499. for (i = 0; i < 4; i ++)
  5500. {
  5501. ptr = Univ_ulong_to_str (IP_GET_SRC_ADDR (ip_hdrp, i), ptr, 10);
  5502. * ptr = L'.';
  5503. ptr ++;
  5504. }
  5505. ptr --;
  5506. * ptr = L':';
  5507. ptr ++;
  5508. ptr = Univ_ulong_to_str (UDP_GET_SRC_PORT (udp_hdrp), ptr, 10);
  5509. * ptr = 0;
  5510. if (!IgnorePassword &&
  5511. ctxtp -> params . rct_password != 0 &&
  5512. rct_hdrp -> password != ctxtp -> params . rct_password)
  5513. {
  5514. LOG_MSG (MSG_WARN_RCT_HACK, buf);
  5515. UNIV_PRINT (("RCT hack attempt on port %d from %d.%d.%d.%d:%d",
  5516. UDP_GET_DST_PORT (udp_hdrp),
  5517. IP_GET_SRC_ADDR (ip_hdrp, 0),
  5518. IP_GET_SRC_ADDR (ip_hdrp, 1),
  5519. IP_GET_SRC_ADDR (ip_hdrp, 2),
  5520. IP_GET_SRC_ADDR (ip_hdrp, 3),
  5521. UDP_GET_SRC_PORT (udp_hdrp)));
  5522. }
  5523. /* only log error commands and commands that affect cluster state */
  5524. else if (rct_hdrp -> ioctrl != IOCTL_CVY_QUERY)
  5525. {
  5526. PWSTR cmd;
  5527. switch (rct_hdrp -> ioctrl)
  5528. {
  5529. case IOCTL_CVY_CLUSTER_ON:
  5530. cmd = L"START";
  5531. break;
  5532. case IOCTL_CVY_CLUSTER_OFF:
  5533. cmd = L"STOP";
  5534. break;
  5535. case IOCTL_CVY_CLUSTER_DRAIN:
  5536. cmd = L"DRAINSTOP";
  5537. break;
  5538. case IOCTL_CVY_PORT_ON:
  5539. cmd = L"ENABLE";
  5540. break;
  5541. case IOCTL_CVY_PORT_SET:
  5542. cmd = L"ADJUST";
  5543. break;
  5544. case IOCTL_CVY_PORT_OFF:
  5545. cmd = L"DISABLE";
  5546. break;
  5547. case IOCTL_CVY_PORT_DRAIN:
  5548. cmd = L"DRAIN";
  5549. break;
  5550. case IOCTL_CVY_QUERY:
  5551. cmd = L"QUERY";
  5552. break;
  5553. case IOCTL_CVY_CLUSTER_SUSPEND:
  5554. cmd = L"SUSPEND";
  5555. break;
  5556. case IOCTL_CVY_CLUSTER_RESUME:
  5557. cmd = L"RESUME";
  5558. break;
  5559. default:
  5560. cmd = L"UNKNOWN";
  5561. break;
  5562. }
  5563. LOG_MSGS (MSG_INFO_RCT_RCVD, cmd, buf);
  5564. UNIV_PRINT (("RCT command %x port %d from %d.%d.%d.%d:%d",
  5565. rct_hdrp -> ioctrl,
  5566. UDP_GET_DST_PORT (udp_hdrp),
  5567. IP_GET_SRC_ADDR (ip_hdrp, 0),
  5568. IP_GET_SRC_ADDR (ip_hdrp, 1),
  5569. IP_GET_SRC_ADDR (ip_hdrp, 2),
  5570. IP_GET_SRC_ADDR (ip_hdrp, 3),
  5571. UDP_GET_SRC_PORT (udp_hdrp)));
  5572. }
  5573. }
  5574. ctxtp -> rct_last_addr = rct_hdrp -> addr;
  5575. ctxtp -> rct_last_id = rct_hdrp -> id;
  5576. /* make sure remote control password matches ours */
  5577. if (!IgnorePassword &&
  5578. ctxtp -> params . rct_password != 0 &&
  5579. rct_hdrp -> password != ctxtp -> params . rct_password)
  5580. {
  5581. rct_hdrp -> ctrl . ret_code = IOCTL_CVY_BAD_PASSWORD;
  5582. goto send;
  5583. }
  5584. if (rct_hdrp->version == CVY_NT40_VERSION_FULL) {
  5585. /* Make sure that the packet length is what we expect, or we may fault. */
  5586. if (len < NLB_NT40_RCTL_PACKET_LEN(ip_hdrp)) {
  5587. UNIV_PRINT(("NT 4.0 remote control packet not expected length: got %d bytes, expected %d bytes\n", len, NLB_NT40_RCTL_PACKET_LEN(ip_hdrp)));
  5588. goto quit;
  5589. }
  5590. /* If this remote control packet came from an NT 4.0 host, check our current effective version
  5591. and drop it if we are operating in a Whistler-specific mode (virtual clusters, BDA, etc.). */
  5592. if (ctxtp->params.effective_ver == CVY_VERSION_FULL &&
  5593. (rct_hdrp->ioctrl == IOCTL_CVY_PORT_ON ||
  5594. rct_hdrp->ioctrl == IOCTL_CVY_PORT_OFF ||
  5595. rct_hdrp->ioctrl == IOCTL_CVY_PORT_SET ||
  5596. rct_hdrp->ioctrl == IOCTL_CVY_PORT_DRAIN))
  5597. goto quit;
  5598. /* Otherwise, perform the operation. Since this request came from a win2K/NT4 host, then hardcode
  5599. the VIP, which should be ignored by Main_ctrl since we aren't using Virtual clusters. */
  5600. else
  5601. status = Main_ctrl(ctxtp, rct_hdrp->ioctrl, &rct_hdrp->ctrl, NULL);
  5602. } else if (rct_hdrp->version == CVY_WIN2K_VERSION_FULL) {
  5603. /* Make sure that the packet length is what we expect, or we may fault. */
  5604. if (len < NLB_WIN2K_RCTL_PACKET_LEN(ip_hdrp)) {
  5605. UNIV_PRINT(("Windows 2000 remote control packet not expected length: got %d bytes, expected %d bytes\n", len, NLB_WIN2K_RCTL_PACKET_LEN(ip_hdrp)));
  5606. goto quit;
  5607. }
  5608. /* If this remote control packet came from an Win2k host, check our current effective version
  5609. and drop it if we are operating in a Whistler-specific mode (virtual clusters, BDA, etc.). */
  5610. if (ctxtp->params.effective_ver == CVY_VERSION_FULL &&
  5611. (rct_hdrp->ioctrl == IOCTL_CVY_PORT_ON ||
  5612. rct_hdrp->ioctrl == IOCTL_CVY_PORT_OFF ||
  5613. rct_hdrp->ioctrl == IOCTL_CVY_PORT_SET ||
  5614. rct_hdrp->ioctrl == IOCTL_CVY_PORT_DRAIN))
  5615. goto quit;
  5616. /* Otherwise, perform the operation. Since this request came from a win2K/NT4 host, then hardcode
  5617. the VIP, which should be ignored by Main_ctrl since we aren't using Virtual clusters. */
  5618. else
  5619. status = Main_ctrl(ctxtp, rct_hdrp->ioctrl, &rct_hdrp->ctrl, NULL);
  5620. } else {
  5621. /* Make sure that the packet length is what we expect, or we may fault. */
  5622. if (len < NLB_WINXP_RCTL_PACKET_LEN(ip_hdrp)) {
  5623. UNIV_PRINT(("Windows XP remote control packet not expected length: got %d bytes, expected %d bytes\n", len, NLB_WINXP_RCTL_PACKET_LEN(ip_hdrp)));
  5624. goto quit;
  5625. }
  5626. /* Perform the operation. The virtual IP address is stored in the remote control
  5627. buffer, not in the IOCTL buffer for reasons of backward compatibility. */
  5628. status = Main_ctrl(ctxtp, rct_hdrp->ioctrl, &rct_hdrp->ctrl, &rct_hdrp->options);
  5629. }
  5630. /* if did not succeed - just drop the packet - client will timeout and
  5631. resend the request */
  5632. if (status != NDIS_STATUS_SUCCESS)
  5633. goto quit;
  5634. send:
  5635. rct_hdrp -> version = CVY_VERSION_FULL;
  5636. rct_hdrp -> host = ctxtp -> params . host_priority;
  5637. rct_hdrp -> addr = ctxtp -> ded_ip_addr;
  5638. /* flip source and destination MAC, IP addresses and UDP ports to prepare
  5639. for sending this message back */
  5640. soff = CVY_MAC_SRC_OFF (ctxtp -> medium);
  5641. doff = CVY_MAC_DST_OFF (ctxtp -> medium);
  5642. /* V2.0.6 recoded for clarity */
  5643. if (ctxtp -> params . mcast_support)
  5644. {
  5645. if (CVY_MAC_ADDR_BCAST (ctxtp -> medium, mac_hdrp + doff))
  5646. CVY_MAC_ADDR_COPY (ctxtp -> medium, & tmp_mac, & ctxtp -> ded_mac_addr);
  5647. else
  5648. CVY_MAC_ADDR_COPY (ctxtp -> medium, & tmp_mac, mac_hdrp + doff);
  5649. CVY_MAC_ADDR_COPY (ctxtp -> medium, mac_hdrp + doff, mac_hdrp + soff);
  5650. CVY_MAC_ADDR_COPY (ctxtp -> medium, mac_hdrp + soff, & tmp_mac);
  5651. }
  5652. else
  5653. {
  5654. if (! CVY_MAC_ADDR_BCAST (ctxtp -> medium, mac_hdrp + doff))
  5655. {
  5656. CVY_MAC_ADDR_COPY (ctxtp -> medium, & tmp_mac, mac_hdrp + doff);
  5657. CVY_MAC_ADDR_COPY (ctxtp -> medium, mac_hdrp + doff, mac_hdrp + soff);
  5658. }
  5659. else
  5660. CVY_MAC_ADDR_COPY (ctxtp -> medium, & tmp_mac, & ctxtp -> ded_mac_addr);
  5661. /* V2.0.6 spoof source mac to prevent switches from getting confused */
  5662. if (ctxtp -> params . mask_src_mac &&
  5663. CVY_MAC_ADDR_COMP (ctxtp -> medium, & tmp_mac, & ctxtp -> cl_mac_addr))
  5664. {
  5665. CVY_MAC_ADDR_LAA_SET (ctxtp -> medium, mac_hdrp + soff);
  5666. * ((PUCHAR) (mac_hdrp + soff + 1)) = (UCHAR) ctxtp -> params . host_priority;
  5667. * ((PULONG) (mac_hdrp + soff + 2)) = ctxtp -> cl_ip_addr;
  5668. }
  5669. else
  5670. CVY_MAC_ADDR_COPY (ctxtp -> medium, mac_hdrp + soff, & tmp_mac);
  5671. }
  5672. /* 64-bit -- ramkrish */
  5673. if (tmp_dst_addr == TCPIP_BCAST_ADDR)
  5674. {
  5675. tmp_dst_addr = ctxtp -> cl_ip_addr;
  5676. if (ctxtp -> params . mcast_support)
  5677. IP_SET_DST_ADDR_64 (ip_hdrp, tmp_src_addr); /* 64-bit -- ramkrish */
  5678. }
  5679. else
  5680. IP_SET_DST_ADDR_64 (ip_hdrp, tmp_src_addr); /* 64-bit -- ramkrish */
  5681. IP_SET_SRC_ADDR_64 (ip_hdrp, tmp_dst_addr);
  5682. checksum = Tcpip_chksum (& ctxtp -> tcpip, ip_hdrp, NULL, TCPIP_PROTOCOL_IP);
  5683. IP_SET_CHKSUM (ip_hdrp, checksum);
  5684. /* 64-bit -- ramkrish */
  5685. tmp_src_port = (USHORT) UDP_GET_SRC_PORT (udp_hdrp);
  5686. tmp_dst_port = (USHORT) UDP_GET_DST_PORT (udp_hdrp);
  5687. UDP_SET_SRC_PORT_64 (udp_hdrp, tmp_dst_port);
  5688. UDP_SET_DST_PORT_64 (udp_hdrp, tmp_src_port);
  5689. checksum = Tcpip_chksum (& ctxtp -> tcpip, ip_hdrp, (PUCHAR) udp_hdrp, TCPIP_PROTOCOL_UDP);
  5690. UDP_SET_CHKSUM (udp_hdrp, checksum);
  5691. #if defined(TRACE_RCT)
  5692. DbgPrint ("(RCT) sending reply to %d.%d.%d.%d:%d [%02x-%02x-%02x-%02x-%02x-%02x]\n",
  5693. IP_GET_DST_ADDR (ip_hdrp, 0),
  5694. IP_GET_DST_ADDR (ip_hdrp, 1),
  5695. IP_GET_DST_ADDR (ip_hdrp, 2),
  5696. IP_GET_DST_ADDR (ip_hdrp, 3),
  5697. UDP_GET_DST_PORT (udp_hdrp),
  5698. * (mac_hdrp + doff + 0),
  5699. * (mac_hdrp + doff + 1),
  5700. * (mac_hdrp + doff + 2),
  5701. * (mac_hdrp + doff + 3),
  5702. * (mac_hdrp + doff + 4),
  5703. * (mac_hdrp + doff + 5));
  5704. DbgPrint (" from %d.%d.%d.%d:%d [%02x-%02x-%02x-%02x-%02x-%02x]\n",
  5705. IP_GET_SRC_ADDR (ip_hdrp, 0),
  5706. IP_GET_SRC_ADDR (ip_hdrp, 1),
  5707. IP_GET_SRC_ADDR (ip_hdrp, 2),
  5708. IP_GET_SRC_ADDR (ip_hdrp, 3),
  5709. UDP_GET_SRC_PORT (udp_hdrp),
  5710. * (mac_hdrp + soff + 0),
  5711. * (mac_hdrp + soff + 1),
  5712. * (mac_hdrp + soff + 2),
  5713. * (mac_hdrp + soff + 3),
  5714. * (mac_hdrp + soff + 4),
  5715. * (mac_hdrp + soff + 5));
  5716. #endif
  5717. /* send back response */
  5718. NdisSend (& status, ctxtp -> mac_handle, packet);
  5719. quit:
  5720. /* note that we have to put packet back 'unoptimized' way since we are
  5721. running at PASSIVE IRQL from RecvComplete */
  5722. if (status != NDIS_STATUS_PENDING)
  5723. {
  5724. UNIV_PRINT (("Main_ctrl_recv: packet not pending\n"));
  5725. Main_packet_put (ctxtp, packet, TRUE, status);
  5726. }
  5727. } /* end Main_ctrl_recv */
  5728. // ###### code added for multiple nic support - ramkrish
  5729. INT Main_adapter_alloc (
  5730. PWSTR device_name)
  5731. {
  5732. INT i;
  5733. UNIV_PRINT (("Main_adapter_alloc: for %ls", device_name));
  5734. NdisAcquireSpinLock (& univ_bind_lock);
  5735. if (univ_adapters_count == CVY_MAX_ADAPTERS)
  5736. {
  5737. NdisReleaseSpinLock (& univ_bind_lock);
  5738. return MAIN_ADAPTER_NOT_FOUND;
  5739. }
  5740. NdisReleaseSpinLock (& univ_bind_lock);
  5741. for (i = 0 ; i < CVY_MAX_ADAPTERS; i++)
  5742. {
  5743. NdisAcquireSpinLock (& univ_bind_lock);
  5744. if (univ_adapters [i] . used == FALSE)
  5745. {
  5746. univ_adapters [i] . used = TRUE;
  5747. univ_adapters_count ++;
  5748. NdisReleaseSpinLock (& univ_bind_lock);
  5749. break;
  5750. }
  5751. NdisReleaseSpinLock (& univ_bind_lock);
  5752. }
  5753. if (i >= CVY_MAX_ADAPTERS)
  5754. return MAIN_ADAPTER_NOT_FOUND;
  5755. NdisAcquireSpinLock (& univ_bind_lock);
  5756. univ_adapters [i] . bound = FALSE;
  5757. univ_adapters [i] . inited = FALSE;
  5758. univ_adapters [i] . announced = FALSE;
  5759. NdisReleaseSpinLock (& univ_bind_lock);
  5760. return i;
  5761. } /* end Main_adapter_alloc */
  5762. INT Main_adapter_get (
  5763. PWSTR device_name)
  5764. {
  5765. INT i;
  5766. NDIS_STRING new_device_name, cur_device_name;
  5767. if (device_name == NULL)
  5768. return MAIN_ADAPTER_NOT_FOUND;
  5769. NdisInitUnicodeString (& new_device_name, device_name);
  5770. for (i = 0 ; i < CVY_MAX_ADAPTERS; i++)
  5771. {
  5772. if (univ_adapters [i] . used &&
  5773. univ_adapters [i] . bound &&
  5774. univ_adapters [i] . inited &&
  5775. univ_adapters [i] . device_name_len)
  5776. {
  5777. NdisInitUnicodeString (& cur_device_name, univ_adapters [i] . device_name);
  5778. if (NdisEqualUnicodeString (& new_device_name, & cur_device_name, TRUE))
  5779. return i;
  5780. }
  5781. }
  5782. return MAIN_ADAPTER_NOT_FOUND; /* adapter not found */
  5783. } /* end Main_adapter_get */
  5784. INT Main_adapter_put (
  5785. PMAIN_ADAPTER adapterp)
  5786. {
  5787. INT adapter_id;
  5788. INT i;
  5789. UNIV_ASSERT (adapterp -> code == MAIN_ADAPTER_CODE);
  5790. for (i = 0 ; i < CVY_MAX_ADAPTERS; i++)
  5791. {
  5792. if (adapterp == univ_adapters + i)
  5793. {
  5794. adapter_id = i;
  5795. UNIV_PRINT (("Main_adapter_put: for adapter id 0x%x\n", adapter_id));
  5796. break;
  5797. }
  5798. }
  5799. if (!adapterp -> used)
  5800. return adapter_id;
  5801. UNIV_ASSERT (univ_adapters_count > 0);
  5802. NdisAcquireSpinLock (& univ_bind_lock);
  5803. univ_adapters [adapter_id] . bound = FALSE;
  5804. univ_adapters [adapter_id] . inited = FALSE;
  5805. univ_adapters [adapter_id] . announced = FALSE;
  5806. univ_adapters [adapter_id] . device_name_len = 0;
  5807. univ_adapters [adapter_id] . device_name = NULL;
  5808. univ_adapters [adapter_id] . ctxtp = NULL;
  5809. univ_adapters [adapter_id] . used = FALSE;
  5810. univ_adapters_count --;
  5811. NdisReleaseSpinLock (& univ_bind_lock);
  5812. return adapter_id;
  5813. } /* end Main_adapter_put*/
  5814. INT Main_adapter_selfbind (
  5815. PWSTR device_name)
  5816. {
  5817. INT i;
  5818. NDIS_STRING new_device_name, cur_device_name;
  5819. UNIV_PRINT (("Main_adapter_selfbind: %ls", device_name));
  5820. if (device_name == NULL)
  5821. return MAIN_ADAPTER_NOT_FOUND;
  5822. NdisInitUnicodeString (& new_device_name, device_name);
  5823. for (i = 0 ; i < CVY_MAX_ADAPTERS; i++)
  5824. {
  5825. if (univ_adapters [i] . used &&
  5826. univ_adapters [i] . bound &&
  5827. univ_adapters [i] . inited)
  5828. {
  5829. NdisInitUnicodeString (& cur_device_name, univ_adapters [i] . ctxtp -> virtual_nic_name);
  5830. UNIV_PRINT (("Main_adapter_selfbind: comparing %ls %ls",
  5831. new_device_name . Buffer,
  5832. cur_device_name . Buffer));
  5833. if (NdisEqualUnicodeString (&new_device_name, &cur_device_name, TRUE))
  5834. return i;
  5835. }
  5836. }
  5837. return MAIN_ADAPTER_NOT_FOUND;
  5838. } /* end Main_adapter_selfbind */
  5839. //+----------------------------------------------------------------------------
  5840. //
  5841. // Function: Main_ApplyChangeWithoutReStart
  5842. //
  5843. // Description: Apply setting changes without re-start.
  5844. // ctxtp -> load_lock should be hold before calling this function
  5845. //
  5846. // Arguments: PMAIN_CTXT ctxtp -
  5847. // CVY_PARAMS* pOldParams - the old parameters
  5848. // const CVY_PARAMS* pCurParam - new parameters
  5849. //
  5850. // Returns: BOOLEAN - TRUE if the change is applied without re-start
  5851. // otherwise, no changes is applied
  5852. //
  5853. // History: fengsun Created Header 9/28/00
  5854. //
  5855. //+----------------------------------------------------------------------------
  5856. BOOLEAN Main_ApplyChangeWithoutReStart(PMAIN_CTXT ctxtp,
  5857. CVY_PARAMS* pOldParams,
  5858. const CVY_PARAMS* pCurParam)
  5859. {
  5860. CVY_RULE OldRules[CVY_MAX_RULES - 1];
  5861. ULONG i;
  5862. if (pOldParams->num_rules != pCurParam->num_rules)
  5863. {
  5864. //
  5865. // Different number of rules
  5866. //
  5867. return FALSE;
  5868. }
  5869. UNIV_ASSERT(sizeof(OldRules) == sizeof(pOldParams->port_rules));
  5870. //
  5871. // Save the old rules and copy the new rule weight over old settings
  5872. //
  5873. RtlCopyMemory(&OldRules, pOldParams->port_rules, sizeof(OldRules));
  5874. for (i=0; i<pCurParam->num_rules; i++)
  5875. {
  5876. if (pCurParam->port_rules[i].mode == CVY_MULTI)
  5877. {
  5878. pOldParams->port_rules[i].mode_data.multi.equal_load =
  5879. pCurParam->port_rules[i].mode_data.multi.equal_load;
  5880. pOldParams->port_rules[i].mode_data.multi.load =
  5881. pCurParam->port_rules[i].mode_data.multi.load;
  5882. }
  5883. }
  5884. if(RtlCompareMemory(pOldParams, pCurParam, sizeof(CVY_PARAMS)) != sizeof(CVY_PARAMS))
  5885. {
  5886. //
  5887. // There are other changes besides port rule weight
  5888. //
  5889. return FALSE;
  5890. }
  5891. //
  5892. // The only change is the weight. Now change the weight
  5893. //
  5894. for (i=0; i<pCurParam->num_rules; i++)
  5895. {
  5896. ULONG NewWeight;
  5897. switch (OldRules[i].mode)
  5898. {
  5899. case CVY_MULTI:
  5900. if (OldRules[i].mode_data.multi.equal_load && pCurParam->port_rules[i].mode_data.multi.equal_load)
  5901. {
  5902. continue; // no weight change
  5903. }
  5904. if (!OldRules[i].mode_data.multi.equal_load &&
  5905. !pCurParam->port_rules[i].mode_data.multi.equal_load &&
  5906. OldRules[i].mode_data.multi.load == pCurParam->port_rules[i].mode_data.multi.load)
  5907. {
  5908. continue; // no weight change
  5909. }
  5910. if (pCurParam->port_rules[i].mode_data.multi.equal_load)
  5911. {
  5912. NewWeight = CVY_EQUAL_LOAD;
  5913. }
  5914. else
  5915. {
  5916. NewWeight = pCurParam->port_rules[i].mode_data.multi.load;
  5917. }
  5918. //
  5919. // Change the weight of the port. Return code ignored
  5920. //
  5921. UNIV_PRINT(("RELOAD: Calling Load_port_change -> VIP=%08x, port=%d, load=%d\n",
  5922. OldRules[i].virtual_ip_addr, OldRules[i].start_port, NewWeight));
  5923. Load_port_change (& ctxtp -> load,
  5924. OldRules[i].virtual_ip_addr,
  5925. OldRules[i].start_port,
  5926. IOCTL_CVY_PORT_SET,
  5927. NewWeight);
  5928. break;
  5929. case CVY_SINGLE:
  5930. case CVY_NEVER:
  5931. default:
  5932. break;
  5933. }
  5934. }
  5935. LOG_MSG(MSG_INFO_CONFIGURE_CHANGE_CONVERGING, MSG_NONE);
  5936. return TRUE;
  5937. }
  5938. #if defined (SBH)
  5939. //+----------------------------------------------------------------------------
  5940. //
  5941. // Function: Main_QueryPerf
  5942. //
  5943. // Description: Query the perfomrance related state from the driver
  5944. //
  5945. // Arguments: MAIN_CTXT ctxtp -
  5946. // PCVY_DRIVER_PERF pPerf -
  5947. //
  5948. // Returns: NDIS_STATUS -
  5949. //
  5950. // History: fengsun Created Header 11/13/00
  5951. //
  5952. //+----------------------------------------------------------------------------
  5953. NDIS_STATUS Main_QueryPerf(
  5954. PMAIN_CTXT ctxtp,
  5955. OUT PCVY_DRIVER_PERF pPerf)
  5956. {
  5957. ULONG i;
  5958. ULONG Status;
  5959. //
  5960. // Call WlbsQuery
  5961. //
  5962. IOCTL_CVY_BUF QueryBuf;
  5963. /* This IOCTL will actually ignore the VIP argument, but set it to a reasonable value anyway. */
  5964. Status = Main_ctrl(ctxtp, IOCTL_CVY_QUERY, &QueryBuf, NULL);
  5965. if (Status != NDIS_STATUS_SUCCESS)
  5966. {
  5967. return Status;
  5968. }
  5969. pPerf->QueryState = QueryBuf.data.query.state;
  5970. pPerf->HostId = QueryBuf.data.query.host_id;
  5971. pPerf->HostMap = QueryBuf.data.query.host_map;
  5972. NdisAcquireSpinLock(&ctxtp -> load_lock);
  5973. //
  5974. // Ethernet header
  5975. //
  5976. UNIV_ASSERT(sizeof(pPerf->EthernetDstAddr) == ETHERNET_ADDRESS_FIELD_SIZE);
  5977. UNIV_ASSERT(sizeof(pPerf->EthernetSrcAddr) == ETHERNET_ADDRESS_FIELD_SIZE);
  5978. RtlCopyMemory (&pPerf->EthernetDstAddr, &ctxtp->media_hdr.ethernet.dst,
  5979. sizeof(pPerf->EthernetDstAddr));
  5980. RtlCopyMemory (&pPerf->EthernetSrcAddr, &ctxtp->media_hdr.ethernet.src,
  5981. sizeof(pPerf->EthernetSrcAddr));
  5982. //
  5983. // Heatbeart
  5984. //
  5985. pPerf->HeartbeatVersion = ctxtp->frame_dscrp->frame_hdr.version;
  5986. pPerf->ClusterIp = ctxtp->frame_dscrp->frame_hdr.cl_ip_addr;
  5987. pPerf->DedicatedIp = ctxtp->frame_dscrp->frame_hdr.ded_ip_addr;
  5988. pPerf->master_id = ctxtp->load_msgp->master_id;
  5989. pPerf->state = ctxtp->load_msgp->state;
  5990. pPerf->nrules = ctxtp->load_msgp->nrules;
  5991. pPerf->UniqueCode = ctxtp->load_msgp->hcode;
  5992. pPerf->pkt_count = ctxtp->load_msgp->pkt_count;
  5993. pPerf->teaming = ctxtp->load_msgp->teaming;
  5994. pPerf->reserved2 = ctxtp->load_msgp->reserved2;
  5995. UNIV_ASSERT(sizeof(pPerf->rcode) == sizeof(ctxtp->load_msgp->rcode));
  5996. RtlCopyMemory(pPerf->rcode, ctxtp->load_msgp->rcode, sizeof(pPerf->rcode));
  5997. UNIV_ASSERT(sizeof(pPerf->cur_map) == sizeof(ctxtp->load_msgp->cur_map));
  5998. RtlCopyMemory(pPerf->cur_map, ctxtp->load_msgp->cur_map, sizeof(pPerf->cur_map));
  5999. UNIV_ASSERT(sizeof(pPerf->new_map) == sizeof(ctxtp->load_msgp->new_map));
  6000. RtlCopyMemory(pPerf->new_map, ctxtp->load_msgp->new_map, sizeof(pPerf->new_map));
  6001. UNIV_ASSERT(sizeof(pPerf->idle_map) == sizeof(ctxtp->load_msgp->idle_map));
  6002. RtlCopyMemory(pPerf->idle_map, ctxtp->load_msgp->idle_map, sizeof(pPerf->idle_map));
  6003. UNIV_ASSERT(sizeof(pPerf->rdy_bins) == sizeof(ctxtp->load_msgp->rdy_bins));
  6004. RtlCopyMemory(pPerf->rdy_bins, ctxtp->load_msgp->rdy_bins, sizeof(pPerf->rdy_bins));
  6005. UNIV_ASSERT(sizeof(pPerf->load_amt) == sizeof(ctxtp->load_msgp->load_amt));
  6006. RtlCopyMemory(pPerf->load_amt, ctxtp->load_msgp->load_amt, sizeof(pPerf->load_amt));
  6007. UNIV_ASSERT(sizeof(pPerf->pg_rsvd1) == sizeof(ctxtp->load_msgp->pg_rsvd1));
  6008. RtlCopyMemory(pPerf->pg_rsvd1, ctxtp->load_msgp->pg_rsvd1, sizeof(pPerf->pg_rsvd1));
  6009. //
  6010. // Load module
  6011. //
  6012. pPerf->Convergence = 0;
  6013. pPerf->nDescAllocated = ctxtp->load.nqalloc * ctxtp->load.dscr_per_alloc+
  6014. CVY_MAX_CHASH+CVY_INIT_QCONN;
  6015. pPerf->nDescInUse = ctxtp->load.nconn;
  6016. pPerf->PacketCount = ctxtp->load.pkt_count;
  6017. pPerf->DirtyClientWaiting = ctxtp->load.cln_waiting;
  6018. UNIV_ASSERT(sizeof(pPerf->CurrentMap[i]) ==
  6019. sizeof(ctxtp->load.pg_state[0].cur_map));
  6020. for (i=0; i<ctxtp->load_msgp->nrules; i++)
  6021. {
  6022. pPerf->AllIdleMap[i] = ctxtp->load.pg_state[i].all_idle_map;
  6023. RtlCopyMemory(pPerf->CurrentMap[i], ctxtp->load.pg_state[i].cur_map,
  6024. sizeof(pPerf->CurrentMap[i]));
  6025. }
  6026. NdisReleaseSpinLock (&ctxtp -> load_lock);
  6027. return NDIS_STATUS_SUCCESS;
  6028. }
  6029. #endif /* SBH */