mcast.c 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372
  1. /*++
  2. Copyright (c) 2017 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. mcast.c
  9. Abstract:
  10. This module implements generic multicast support for sockets and links.
  11. Author:
  12. Chris Stevens 25-Aug-2017
  13. Environment:
  14. Kernel
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include <minoca/kernel/driver.h>
  20. #include "netcore.h"
  21. //
  22. // --------------------------------------------------------------------- Macros
  23. //
  24. //
  25. // ---------------------------------------------------------------- Definitions
  26. //
  27. //
  28. // ------------------------------------------------------ Data Type Definitions
  29. //
  30. //
  31. // ----------------------------------------------- Internal Function Prototypes
  32. //
  33. KSTATUS
  34. NetpFindLinkForMulticastRequest (
  35. PNET_NETWORK_ENTRY Network,
  36. PNET_SOCKET_MULTICAST_REQUEST Request,
  37. PNET_LINK_LOCAL_ADDRESS LinkResult
  38. );
  39. KSTATUS
  40. NetpUpdateMulticastAddressFilters (
  41. PNET_LINK Link
  42. );
  43. PNET_SOCKET_MULTICAST_GROUP
  44. NetpFindSocketMulticastGroup (
  45. PNET_SOCKET Socket,
  46. PNET_LINK Link,
  47. PNET_LINK_ADDRESS_ENTRY LinkAddress,
  48. PNETWORK_ADDRESS MulticastAddress
  49. );
  50. PNET_SOCKET_MULTICAST_GROUP
  51. NetpCreateSocketMulticastGroup (
  52. PNET_LINK Link,
  53. PNET_LINK_ADDRESS_ENTRY LinkAddress,
  54. PNETWORK_ADDRESS MulticastAddress
  55. );
  56. VOID
  57. NetpDestroySocketMulticastGroup (
  58. PNET_SOCKET_MULTICAST_GROUP Group
  59. );
  60. KSTATUS
  61. NetpAcquireSocketMulticastLock (
  62. PNET_SOCKET Socket
  63. );
  64. VOID
  65. NetpReleaseSocketMulticastLock (
  66. PNET_SOCKET Socket
  67. );
  68. PNET_LINK_MULTICAST_GROUP
  69. NetpFindLinkMulticastGroup (
  70. PNET_LINK Link,
  71. PNET_LINK_ADDRESS_ENTRY LinkAddress,
  72. PNETWORK_ADDRESS MulticastAddress
  73. );
  74. //
  75. // -------------------------------------------------------------------- Globals
  76. //
  77. //
  78. // ------------------------------------------------------------------ Functions
  79. //
  80. NET_API
  81. KSTATUS
  82. NetInitializeMulticastSocket (
  83. PNET_SOCKET Socket
  84. )
  85. /*++
  86. Routine Description:
  87. This routine initializes a network socket's multicast information.
  88. Arguments:
  89. Socket - Supplies a pointer to the network socket to initialize.
  90. Return Value:
  91. Status code.
  92. --*/
  93. {
  94. ASSERT(Socket->MulticastLock == NULL);
  95. ASSERT(Socket->MulticastInterface.LinkInformation.Link == NULL);
  96. RtlAtomicOr32(&(Socket->Flags), NET_SOCKET_FLAG_MULTICAST_LOOPBACK);
  97. INITIALIZE_LIST_HEAD(&(Socket->MulticastGroupList));
  98. return STATUS_SUCCESS;
  99. }
  100. NET_API
  101. VOID
  102. NetDestroyMulticastSocket (
  103. PNET_SOCKET Socket
  104. )
  105. /*++
  106. Routine Description:
  107. This routine destroys all the multicast state associated with the given
  108. socket.
  109. Arguments:
  110. Socket - Supplies a pointer to the socket whose multicast state is to be
  111. destroyed.
  112. Return Value:
  113. None.
  114. --*/
  115. {
  116. PNET_SOCKET_MULTICAST_GROUP Group;
  117. PNET_LINK Link;
  118. Link = Socket->MulticastInterface.LinkInformation.Link;
  119. if (Link != NULL) {
  120. NetLinkReleaseReference(Link);
  121. }
  122. if (LIST_EMPTY(&(Socket->MulticastGroupList)) != FALSE) {
  123. goto DestroyMulticastSocket;
  124. }
  125. ASSERT(Socket->MulticastLock != NULL);
  126. //
  127. // Run through the local list, leave each multicast group and destroy the
  128. // group structures.
  129. //
  130. while (LIST_EMPTY(&(Socket->MulticastGroupList)) == FALSE) {
  131. Group = LIST_VALUE(Socket->MulticastGroupList.Next,
  132. NET_SOCKET_MULTICAST_GROUP,
  133. ListEntry);
  134. LIST_REMOVE(&(Group->ListEntry));
  135. NetLeaveLinkMulticastGroup(Group->Link,
  136. Group->LinkAddress,
  137. &(Group->MulticastAddress));
  138. NetpDestroySocketMulticastGroup(Group);
  139. }
  140. DestroyMulticastSocket:
  141. if (Socket->MulticastLock != NULL) {
  142. KeDestroyQueuedLock(Socket->MulticastLock);
  143. }
  144. return;
  145. }
  146. NET_API
  147. KSTATUS
  148. NetJoinSocketMulticastGroup (
  149. PNET_SOCKET Socket,
  150. PNET_SOCKET_MULTICAST_REQUEST Request
  151. )
  152. /*++
  153. Routine Description:
  154. This routine joins the given socket to a multicast group.
  155. Arguments:
  156. Socket - Supplies a pointer to a socket.
  157. Request - Supplies a pointer to the multicast join request. This stores
  158. the address of the multicast group to join along with interface
  159. information to indicate which link should join the group.
  160. Return Value:
  161. Status code.
  162. --*/
  163. {
  164. PNET_SOCKET_MULTICAST_GROUP Group;
  165. NET_LINK_LOCAL_ADDRESS LinkResult;
  166. BOOL LockHeld;
  167. PNET_NETWORK_ENTRY Network;
  168. PNET_SOCKET_MULTICAST_GROUP NewGroup;
  169. KSTATUS Status;
  170. LinkResult.Link = NULL;
  171. LockHeld = FALSE;
  172. Network = Socket->Network;
  173. NewGroup = NULL;
  174. //
  175. // Attempt to find a network link that can reach the multicast address, or
  176. // find the one specified by the request.
  177. //
  178. Status = NetpFindLinkForMulticastRequest(Network, Request, &LinkResult);
  179. if (!KSUCCESS(Status)) {
  180. Status = STATUS_NO_SUCH_DEVICE;
  181. goto SocketJoinMulticastGroupEnd;
  182. }
  183. Status = NetpAcquireSocketMulticastLock(Socket);
  184. if (!KSUCCESS(Status)) {
  185. goto SocketJoinMulticastGroupEnd;
  186. }
  187. LockHeld = TRUE;
  188. //
  189. // Check to see if this socket already joined the group.
  190. //
  191. Group = NetpFindSocketMulticastGroup(Socket,
  192. LinkResult.Link,
  193. LinkResult.LinkAddress,
  194. &(Request->MulticastAddress));
  195. if (Group != NULL) {
  196. Status = STATUS_ADDRESS_IN_USE;
  197. goto SocketJoinMulticastGroupEnd;
  198. }
  199. //
  200. // Prepare for success and allocate a new socket multicast group.
  201. //
  202. NewGroup = NetpCreateSocketMulticastGroup(LinkResult.Link,
  203. LinkResult.LinkAddress,
  204. &(Request->MulticastAddress));
  205. if (NewGroup == NULL) {
  206. Status = STATUS_INSUFFICIENT_RESOURCES;
  207. goto SocketJoinMulticastGroupEnd;
  208. }
  209. //
  210. // Before officially adding the multicast group to the socket, make sure
  211. // the link joins the multicast group as well. This requires updating the
  212. // hardware filters and sending network-specific messages to alert routers
  213. // that this node is joining the multicast group. This all must happen with
  214. // the socket's multicast link lock held to serialze with other join and
  215. // leave requests.
  216. //
  217. Status = NetJoinLinkMulticastGroup(LinkResult.Link,
  218. LinkResult.LinkAddress,
  219. &(Request->MulticastAddress));
  220. if (!KSUCCESS(Status)) {
  221. goto SocketJoinMulticastGroupEnd;
  222. }
  223. INSERT_BEFORE(&(NewGroup->ListEntry),
  224. &(Socket->MulticastGroupList));
  225. SocketJoinMulticastGroupEnd:
  226. if (LockHeld != FALSE) {
  227. NetpReleaseSocketMulticastLock(Socket);
  228. }
  229. if (LinkResult.Link != NULL) {
  230. NetLinkReleaseReference(LinkResult.Link);
  231. }
  232. if (!KSUCCESS(Status)) {
  233. if (NewGroup != NULL) {
  234. NetpDestroySocketMulticastGroup(NewGroup);
  235. }
  236. }
  237. return Status;
  238. }
  239. NET_API
  240. KSTATUS
  241. NetLeaveSocketMulticastGroup (
  242. PNET_SOCKET Socket,
  243. PNET_SOCKET_MULTICAST_REQUEST Request
  244. )
  245. /*++
  246. Routine Description:
  247. This routine removes the given socket from a multicast group.
  248. Arguments:
  249. Socket - Supplies a pointer to a socket.
  250. Request - Supplies a pointer to the multicast leave request. This stores
  251. the multicast group address to leave and the address of the interface
  252. on which the socket joined the group.
  253. Return Value:
  254. Status code.
  255. --*/
  256. {
  257. PNET_SOCKET_MULTICAST_GROUP Group;
  258. NET_LINK_LOCAL_ADDRESS LinkResult;
  259. BOOL LockHeld;
  260. PNET_NETWORK_ENTRY Network;
  261. KSTATUS Status;
  262. Group = NULL;
  263. LinkResult.Link = NULL;
  264. LockHeld = FALSE;
  265. Network = Socket->Network;
  266. //
  267. // If the multicast group list is empty, then this socket never joined any
  268. // multicast groups.
  269. //
  270. if (LIST_EMPTY(&(Socket->MulticastGroupList)) != FALSE) {
  271. Status = STATUS_INVALID_ADDRESS;
  272. goto SocketLeaveMulticastGroupEnd;
  273. }
  274. ASSERT(Socket->MulticastLock != NULL);
  275. //
  276. // Attempt to find a network link that can reach the multicast address, or
  277. // find the one specified by the request.
  278. //
  279. Status = NetpFindLinkForMulticastRequest(Network, Request, &LinkResult);
  280. if (!KSUCCESS(Status)) {
  281. Status = STATUS_NO_SUCH_DEVICE;
  282. goto SocketLeaveMulticastGroupEnd;
  283. }
  284. //
  285. // Search through the multicast groups for a matching entry.
  286. //
  287. Status = NetpAcquireSocketMulticastLock(Socket);
  288. if (!KSUCCESS(Status)) {
  289. goto SocketLeaveMulticastGroupEnd;
  290. }
  291. LockHeld = TRUE;
  292. Group = NetpFindSocketMulticastGroup(Socket,
  293. LinkResult.Link,
  294. LinkResult.LinkAddress,
  295. &(Request->MulticastAddress));
  296. if (Group == NULL) {
  297. Status = STATUS_INVALID_ADDRESS;
  298. goto SocketLeaveMulticastGroupEnd;
  299. }
  300. //
  301. // Notify the link that this socket is leaving the group. This will trigger
  302. // any network-specific protocol actions. The socket's multicast lock is
  303. // held over this operation, but there shouldn't be high contention on an
  304. // individual socket's lock.
  305. //
  306. Status = NetLeaveLinkMulticastGroup(Group->Link,
  307. Group->LinkAddress,
  308. &(Group->MulticastAddress));
  309. if (!KSUCCESS(Status)) {
  310. goto SocketLeaveMulticastGroupEnd;
  311. }
  312. //
  313. // Remove the group from the list.
  314. //
  315. LIST_REMOVE(&(Group->ListEntry));
  316. NetpDestroySocketMulticastGroup(Group);
  317. SocketLeaveMulticastGroupEnd:
  318. if (LockHeld != FALSE) {
  319. NetpReleaseSocketMulticastLock(Socket);
  320. }
  321. if (LinkResult.Link != NULL) {
  322. NetLinkReleaseReference(LinkResult.Link);
  323. }
  324. return Status;
  325. }
  326. NET_API
  327. KSTATUS
  328. NetSetSocketMulticastInterface (
  329. PNET_SOCKET Socket,
  330. PNET_SOCKET_MULTICAST_REQUEST Request
  331. )
  332. /*++
  333. Routine Description:
  334. This routine sets a socket's default multicast interface.
  335. Arguments:
  336. Socket - Supplies a pointer a socket.
  337. Request - Supplies a pointer to the request which dictates the default
  338. interface.
  339. Return Value:
  340. Status code.
  341. --*/
  342. {
  343. NET_ADDRESS_TYPE AddressType;
  344. NET_LINK_LOCAL_ADDRESS LinkResult;
  345. NET_SOCKET_LINK_OVERRIDE NewInterface;
  346. PNET_LINK OldInterfaceLink;
  347. KSTATUS Status;
  348. NewInterface.LinkInformation.Link = NULL;
  349. LinkResult.Link = NULL;
  350. //
  351. // Find the appropriate link and link address entry for the specified
  352. // interface. If no interface is specified (an ID of zero and the
  353. // unspecified interface address), then reset the multicast interface.
  354. //
  355. AddressType = NetAddressUnicast;
  356. if (Request->InterfaceId == 0) {
  357. AddressType = Socket->Network->Interface.GetAddressType(
  358. NULL,
  359. NULL,
  360. &(Request->InterfaceAddress));
  361. }
  362. if (AddressType == NetAddressAny) {
  363. RtlZeroMemory(&NewInterface, sizeof(NET_SOCKET_LINK_OVERRIDE));
  364. } else {
  365. Status = NetpFindLinkForMulticastRequest(Socket->Network,
  366. Request,
  367. &LinkResult);
  368. if (!KSUCCESS(Status)) {
  369. goto SetSocketMulticastInterface;
  370. }
  371. NetInitializeSocketLinkOverride(Socket, &LinkResult, &NewInterface);
  372. }
  373. Status = NetpAcquireSocketMulticastLock(Socket);
  374. if (!KSUCCESS(Status)) {
  375. goto SetSocketMulticastInterface;
  376. }
  377. OldInterfaceLink = Socket->MulticastInterface.LinkInformation.Link;
  378. RtlCopyMemory(&(Socket->MulticastInterface),
  379. &NewInterface,
  380. sizeof(NET_SOCKET_LINK_OVERRIDE));
  381. NetpReleaseSocketMulticastLock(Socket);
  382. if (OldInterfaceLink != NULL) {
  383. NetLinkReleaseReference(OldInterfaceLink);
  384. }
  385. //
  386. // The link reference was passed to the socket's multicast interface.
  387. //
  388. NewInterface.LinkInformation.Link = NULL;
  389. SetSocketMulticastInterface:
  390. if (NewInterface.LinkInformation.Link != NULL) {
  391. NetLinkReleaseReference(NewInterface.LinkInformation.Link);
  392. }
  393. if (LinkResult.Link != NULL) {
  394. NetLinkReleaseReference(LinkResult.Link);
  395. }
  396. return Status;
  397. }
  398. NET_API
  399. KSTATUS
  400. NetGetSocketMulticastInterface (
  401. PNET_SOCKET Socket,
  402. PNET_SOCKET_MULTICAST_REQUEST Request
  403. )
  404. /*++
  405. Routine Description:
  406. This routine gets a socket's default multicast interface.
  407. Arguments:
  408. Socket - Supplies a pointer a socket.
  409. Request - Supplies a pointer that receives the current interface.
  410. Return Value:
  411. Status code.
  412. --*/
  413. {
  414. PNET_LINK Link;
  415. KSTATUS Status;
  416. Status = NetpAcquireSocketMulticastLock(Socket);
  417. if (!KSUCCESS(Status)) {
  418. goto GetSocketMulticastInterface;
  419. }
  420. RtlZeroMemory(&(Request->MulticastAddress), sizeof(NETWORK_ADDRESS));
  421. RtlCopyMemory(&(Request->InterfaceAddress),
  422. &(Socket->MulticastInterface.LinkInformation.SendAddress),
  423. sizeof(NETWORK_ADDRESS));
  424. Link = Socket->MulticastInterface.LinkInformation.Link;
  425. Request->InterfaceId = IoGetDeviceNumericId(Link->Properties.Device);
  426. NetpReleaseSocketMulticastLock(Socket);
  427. GetSocketMulticastInterface:
  428. return Status;
  429. }
  430. NET_API
  431. KSTATUS
  432. NetJoinLinkMulticastGroup (
  433. PNET_LINK Link,
  434. PNET_LINK_ADDRESS_ENTRY LinkAddress,
  435. PNETWORK_ADDRESS MulticastAddress
  436. )
  437. /*++
  438. Routine Description:
  439. This routine joins the multicast group on a link. If this is the first
  440. request to join the supplied multicast group on the link, then the hardware
  441. is reprogrammed to include messages to the multicast group's physical layer
  442. address and the network is invoked to announce the join via a
  443. network-specific protocol.
  444. Arguments:
  445. Link - Supplies a pointer to the network link joining the multicast group.
  446. LinkAddress - Supplies a pointer to the link address entry via which the
  447. link will join the group.
  448. MulticastAddress - Supplies a pointer to the multicast address of the group
  449. to join.
  450. Return Value:
  451. Status code.
  452. --*/
  453. {
  454. PNET_LINK_MULTICAST_GROUP Group;
  455. BOOL LockHeld;
  456. PNET_NETWORK_ENTRY Network;
  457. PNET_LINK_MULTICAST_GROUP NewGroup;
  458. NET_NETWORK_MULTICAST_REQUEST Request;
  459. KSTATUS Status;
  460. LockHeld = FALSE;
  461. Network = LinkAddress->Network;
  462. NewGroup = NULL;
  463. //
  464. // This isn't going to get very far without network multicast support or
  465. // hardware filtering/promiscuous support.
  466. //
  467. if ((Network->Interface.JoinLeaveMulticastGroup == NULL) ||
  468. ((Link->Properties.Capabilities &
  469. NET_LINK_CAPABILITY_PROMISCUOUS_MODE) == 0)) {
  470. Status = STATUS_NOT_SUPPORTED_BY_PROTOCOL;
  471. goto LinkJoinMulticastGroupEnd;
  472. }
  473. //
  474. // Search the link for the multicast group. If a matching group is found,
  475. // add to the count for this join request. A previous join already updated
  476. // the hardware filters and kicked off the network-specific join protocol.
  477. //
  478. while (TRUE) {
  479. KeAcquireQueuedLock(Link->QueuedLock);
  480. LockHeld = TRUE;
  481. Group = NetpFindLinkMulticastGroup(Link, LinkAddress, MulticastAddress);
  482. if (Group != NULL) {
  483. Group->JoinCount += 1;
  484. Status = STATUS_SUCCESS;
  485. goto LinkJoinMulticastGroupEnd;
  486. }
  487. //
  488. // If a group is not found the first time, release the lock and create
  489. // one before looping to search again.
  490. //
  491. if (NewGroup == NULL) {
  492. KeReleaseQueuedLock(Link->QueuedLock);
  493. LockHeld = FALSE;
  494. NewGroup = MmAllocatePagedPool(sizeof(NET_LINK_MULTICAST_GROUP),
  495. NET_CORE_ALLOCATION_TAG);
  496. if (NewGroup == NULL) {
  497. Status = STATUS_INSUFFICIENT_RESOURCES;
  498. goto LinkJoinMulticastGroupEnd;
  499. }
  500. RtlZeroMemory(NewGroup, sizeof(NET_LINK_MULTICAST_GROUP));
  501. NewGroup->LinkAddress = LinkAddress;
  502. NewGroup->JoinCount = 1;
  503. RtlCopyMemory(&(NewGroup->Address),
  504. MulticastAddress,
  505. sizeof(NETWORK_ADDRESS));
  506. continue;
  507. }
  508. //
  509. // No group was found a second time. Add the newly allocated group to
  510. // the link's list.
  511. //
  512. INSERT_BEFORE(&(NewGroup->ListEntry), &(Link->MulticastGroupList));
  513. break;
  514. }
  515. //
  516. // The hardware filters needs to be updated. The filters are updated with
  517. // the lock held as every group's address needs to be sent to the hardware.
  518. // It would also be bad to have a second join call run through before the
  519. // hardware is initialized.
  520. //
  521. Status = NetpUpdateMulticastAddressFilters(Link);
  522. if (!KSUCCESS(Status)) {
  523. LIST_REMOVE(&(NewGroup->ListEntry));
  524. goto LinkJoinMulticastGroupEnd;
  525. }
  526. NewGroup = NULL;
  527. KeReleaseQueuedLock(Link->QueuedLock);
  528. LockHeld = FALSE;
  529. //
  530. // Invoke the network layer to communicate that this link has joined the
  531. // multicast group. If this fails, make an attempt to leave the group.
  532. //
  533. Request.Link = Link;
  534. Request.LinkAddress = LinkAddress;
  535. Request.MulticastAddress = MulticastAddress;
  536. Status = Network->Interface.JoinLeaveMulticastGroup(&Request, TRUE);
  537. if (!KSUCCESS(Status)) {
  538. NetLeaveLinkMulticastGroup(Link, LinkAddress, MulticastAddress);
  539. goto LinkJoinMulticastGroupEnd;
  540. }
  541. LinkJoinMulticastGroupEnd:
  542. if (LockHeld != FALSE) {
  543. KeReleaseQueuedLock(Link->QueuedLock);
  544. }
  545. if (NewGroup != NULL) {
  546. MmFreePagedPool(NewGroup);
  547. }
  548. return Status;
  549. }
  550. NET_API
  551. KSTATUS
  552. NetLeaveLinkMulticastGroup (
  553. PNET_LINK Link,
  554. PNET_LINK_ADDRESS_ENTRY LinkAddress,
  555. PNETWORK_ADDRESS MulticastAddress
  556. )
  557. /*++
  558. Routine Description:
  559. This routine removes a link from a multicast. If this is the last request
  560. to leave a multicast group on the link, then the hardware is reprogrammed
  561. to filter out messages to the multicast group and a network-specific
  562. protocol is invoked to announce the link is leaving the group.
  563. Arguments:
  564. Link - Supplies a pointer to the network link leaving the multicast group.
  565. LinkAddress - Supplies a pointer to the link address entry via which the
  566. link will leave the group.
  567. MulticastAddress - Supplies a pointer to the multicast address of the group
  568. to leave.
  569. Return Value:
  570. Status code.
  571. --*/
  572. {
  573. PNET_LINK_MULTICAST_GROUP Group;
  574. BOOL LockHeld;
  575. PNET_NETWORK_ENTRY Network;
  576. NET_NETWORK_MULTICAST_REQUEST Request;
  577. KSTATUS Status;
  578. LockHeld = FALSE;
  579. Network = LinkAddress->Network;
  580. //
  581. // Search the link for the multicast group. If a matching group is not
  582. // found then the request fails.
  583. //
  584. KeAcquireQueuedLock(Link->QueuedLock);
  585. LockHeld = TRUE;
  586. Group = NetpFindLinkMulticastGroup(Link, LinkAddress, MulticastAddress);
  587. if (Group == NULL) {
  588. Status = STATUS_INVALID_ADDRESS;
  589. goto LinkLeaveMulticastGroupEnd;
  590. }
  591. //
  592. // If this is not the last reference on the group, the call is successful,
  593. // but takes no further action. The link as whole remains joined to the
  594. // multicast group.
  595. //
  596. Group->JoinCount -= 1;
  597. if (Group->JoinCount != 0) {
  598. Status = STATUS_SUCCESS;
  599. goto LinkLeaveMulticastGroupEnd;
  600. }
  601. //
  602. // Otherwise it's time for the group to go.
  603. //
  604. LIST_REMOVE(&(Group->ListEntry));
  605. //
  606. // Now that the group is out of the list, update the filters.
  607. //
  608. Status = NetpUpdateMulticastAddressFilters(Link);
  609. if (!KSUCCESS(Status)) {
  610. Group->JoinCount = 1;
  611. INSERT_BEFORE(&(Group->ListEntry), &(Link->MulticastGroupList));
  612. goto LinkLeaveMulticastGroupEnd;
  613. }
  614. //
  615. // Release the lock and trigger the network-specific work to announce that
  616. // this link has left the group.
  617. //
  618. KeReleaseQueuedLock(Link->QueuedLock);
  619. LockHeld = FALSE;
  620. Request.Link = Link;
  621. Request.LinkAddress = LinkAddress;
  622. Request.MulticastAddress = MulticastAddress;
  623. Network->Interface.JoinLeaveMulticastGroup(&Request, FALSE);
  624. MmFreePagedPool(Group);
  625. LinkLeaveMulticastGroupEnd:
  626. if (LockHeld != FALSE) {
  627. KeReleaseQueuedLock(Link->QueuedLock);
  628. }
  629. return Status;
  630. }
  631. NET_API
  632. VOID
  633. NetDestroyLinkMulticastGroups (
  634. PNET_LINK Link
  635. )
  636. /*++
  637. Routine Description:
  638. This routine destroys the links remaining multicast groups. It is meant to
  639. be called during link destruction and does not attempt to update the MAC
  640. address filters or notify the network. The link should have no references.
  641. Arguments:
  642. Link - Supplies a pointer to the link whose multicast groups are being
  643. destroyed.
  644. Return Value:
  645. None.
  646. --*/
  647. {
  648. PNET_LINK_MULTICAST_GROUP Group;
  649. ASSERT(Link->ReferenceCount == 0);
  650. ASSERT(Link->LinkUp == FALSE);
  651. while (LIST_EMPTY(&(Link->MulticastGroupList)) == FALSE) {
  652. Group = LIST_VALUE(Link->MulticastGroupList.Next,
  653. NET_LINK_MULTICAST_GROUP,
  654. ListEntry);
  655. //
  656. // Any groups still remaining should have a join count from 1. These
  657. // groups were joined when the link was initialized.
  658. //
  659. ASSERT(Group->JoinCount == 1);
  660. LIST_REMOVE(&(Group->ListEntry));
  661. MmFreePagedPool(Group);
  662. }
  663. return;
  664. }
  665. //
  666. // --------------------------------------------------------- Internal Functions
  667. //
  668. KSTATUS
  669. NetpFindLinkForMulticastRequest (
  670. PNET_NETWORK_ENTRY Network,
  671. PNET_SOCKET_MULTICAST_REQUEST Request,
  672. PNET_LINK_LOCAL_ADDRESS LinkResult
  673. )
  674. /*++
  675. Routine Description:
  676. This routine searches for a network link that matches the given multicast
  677. request. If the any address is supplied, then the multicast address will be
  678. used to find a link that can reach it. A reference is taken on the returned
  679. network link. The caller is responsible for releasing the reference.
  680. Arguments:
  681. Network - Supplies a pointer to the network to which the addresses belong.
  682. Request - Supplies the multicast request for which a link needs to be
  683. found.
  684. LinkResult - Supplies a pointer that receives the link information,
  685. including the link, link address entry, and associated local address.
  686. Return Value:
  687. Status code.
  688. --*/
  689. {
  690. NET_ADDRESS_TYPE AddressType;
  691. PDEVICE Device;
  692. PNET_LINK Link;
  693. KSTATUS Status;
  694. //
  695. // The interface ID can be used to find the desired link to use for the
  696. // multicast request.
  697. //
  698. Link = NULL;
  699. if (Request->InterfaceId != 0) {
  700. Device = IoGetDeviceByNumericId(Request->InterfaceId);
  701. if (Device == NULL) {
  702. Status = STATUS_NO_SUCH_DEVICE;
  703. goto FindLinkForMulticastRequest;
  704. }
  705. Status = NetLookupLinkByDevice(Device, &Link);
  706. if (!KSUCCESS(Status)) {
  707. goto FindLinkForMulticastRequest;
  708. }
  709. } else if (Network->Interface.GetAddressType != NULL) {
  710. AddressType = Network->Interface.GetAddressType(
  711. NULL,
  712. NULL,
  713. &(Request->InterfaceAddress));
  714. //
  715. // If the any address is supplied for the interface, find a link that
  716. // can reach the multicast address.
  717. //
  718. if (AddressType == NetAddressAny) {
  719. Status = NetFindLinkForRemoteAddress(&(Request->MulticastAddress),
  720. LinkResult);
  721. if (KSUCCESS(Status)) {
  722. goto FindLinkForMulticastRequest;
  723. }
  724. }
  725. }
  726. //
  727. // Otherwise a link result that matches the given address must be found.
  728. //
  729. Status = NetFindLinkForLocalAddress(&(Request->InterfaceAddress),
  730. Link,
  731. LinkResult);
  732. if (!KSUCCESS(Status)) {
  733. goto FindLinkForMulticastRequest;
  734. }
  735. FindLinkForMulticastRequest:
  736. if (Link != NULL) {
  737. NetLinkReleaseReference(Link);
  738. }
  739. return Status;
  740. }
  741. KSTATUS
  742. NetpUpdateMulticastAddressFilters (
  743. PNET_LINK Link
  744. )
  745. /*++
  746. Routine Description:
  747. This routine updates the given link's address filtering based on the
  748. multicast groups to which the link currently belongs. It will gather a list
  749. of all the physical layer addresses that need to be enabled and pass them
  750. to the hardware for it to update its filters. It falls back to enabling
  751. promiscuous mode if the link does not support multicast address filtering.
  752. Arguments:
  753. Link - Supplies a pointer to the link whose filters are to be updated.
  754. Return Value:
  755. Status code.
  756. --*/
  757. {
  758. PVOID Data;
  759. UINTN DataSize;
  760. ULONG Enable;
  761. PNET_DEVICE_LINK_GET_SET_INFORMATION GetSetInformation;
  762. NET_LINK_INFORMATION_TYPE InformationType;
  763. KSTATUS Status;
  764. ASSERT(KeIsQueuedLockHeld(Link->QueuedLock) != FALSE);
  765. GetSetInformation = Link->Properties.Interface.GetSetInformation;
  766. //
  767. // Before resorting to promiscuous mode, attempt to set the link to
  768. // receive all multicast packets, if supported.
  769. //
  770. if ((Link->Properties.Capabilities &
  771. NET_LINK_CAPABILITY_MULTICAST_ALL) != 0) {
  772. InformationType = NetLinkInformationMulticastAll;
  773. //
  774. // As a last resort, the link should at least support promiscuous mode
  775. // to have allowed a multicast join request to make it this far.
  776. //
  777. } else {
  778. ASSERT((Link->Properties.Capabilities &
  779. NET_LINK_CAPABILITY_PROMISCUOUS_MODE) != 0);
  780. InformationType = NetLinkInformationPromiscuousMode;
  781. }
  782. Enable = FALSE;
  783. if (LIST_EMPTY(&(Link->MulticastGroupList)) == FALSE) {
  784. Enable = TRUE;
  785. }
  786. DataSize = sizeof(ULONG);
  787. Data = (PVOID)&Enable;
  788. Status = GetSetInformation(Link->Properties.DeviceContext,
  789. InformationType,
  790. Data,
  791. &DataSize,
  792. TRUE);
  793. return Status;
  794. }
  795. PNET_SOCKET_MULTICAST_GROUP
  796. NetpFindSocketMulticastGroup (
  797. PNET_SOCKET Socket,
  798. PNET_LINK Link,
  799. PNET_LINK_ADDRESS_ENTRY LinkAddress,
  800. PNETWORK_ADDRESS MulticastAddress
  801. )
  802. /*++
  803. Routine Description:
  804. This routine finds a multicast group in a socket's list of multicast groups.
  805. Arguments:
  806. Socket - Supplies a pointer to the socket to search.
  807. Link - Supplies a pointer to the link associated with the multicast group.
  808. LinkAddress - Supplies a pointer to the link address entry associated with
  809. the multicast group.
  810. MulticastAddress - Supplies a pointer to the multicast address of the group.
  811. Return Value:
  812. Returns a pointer to a socket multicast group on success or NULL on failure.
  813. --*/
  814. {
  815. PLIST_ENTRY CurrentEntry;
  816. PNET_SOCKET_MULTICAST_GROUP Group;
  817. COMPARISON_RESULT Result;
  818. ASSERT(KeIsQueuedLockHeld(Socket->MulticastLock) != FALSE);
  819. CurrentEntry = Socket->MulticastGroupList.Next;
  820. while (CurrentEntry != &(Socket->MulticastGroupList)) {
  821. Group = LIST_VALUE(CurrentEntry, NET_SOCKET_MULTICAST_GROUP, ListEntry);
  822. if ((Group->Link == Link) && (Group->LinkAddress == LinkAddress)) {
  823. Result = NetCompareNetworkAddresses(&(Group->MulticastAddress),
  824. MulticastAddress);
  825. if (Result == ComparisonResultSame) {
  826. return Group;
  827. }
  828. }
  829. CurrentEntry = CurrentEntry->Next;
  830. }
  831. return NULL;
  832. }
  833. PNET_SOCKET_MULTICAST_GROUP
  834. NetpCreateSocketMulticastGroup (
  835. PNET_LINK Link,
  836. PNET_LINK_ADDRESS_ENTRY LinkAddress,
  837. PNETWORK_ADDRESS MulticastAddress
  838. )
  839. /*++
  840. Routine Description:
  841. This routine creates a socket multicast group.
  842. Arguments:
  843. Link - Supplies a pointer to the link on which the socket joined the group.
  844. LinkAddress - Supplies a pointer to the link address on which the socket
  845. joined the group.
  846. MulticastAddress - Supplies a pointer to the multicast group address.
  847. Return Value:
  848. Returns a pointer to the new group on success or NULL on failure.
  849. --*/
  850. {
  851. PNET_SOCKET_MULTICAST_GROUP NewGroup;
  852. //
  853. // Prepare for success and allocate a new socket multicast group.
  854. //
  855. NewGroup = MmAllocatePagedPool(sizeof(NET_SOCKET_MULTICAST_GROUP),
  856. NET_CORE_ALLOCATION_TAG);
  857. if (NewGroup == NULL) {
  858. goto CreateSocketMulticastGroupEnd;
  859. }
  860. NetLinkAddReference(Link);
  861. NewGroup->Link = Link;
  862. NewGroup->LinkAddress = LinkAddress;
  863. RtlCopyMemory(&(NewGroup->MulticastAddress),
  864. MulticastAddress,
  865. sizeof(NETWORK_ADDRESS));
  866. CreateSocketMulticastGroupEnd:
  867. return NewGroup;
  868. }
  869. VOID
  870. NetpDestroySocketMulticastGroup (
  871. PNET_SOCKET_MULTICAST_GROUP Group
  872. )
  873. /*++
  874. Routine Description:
  875. This routine destroys the given socket multicast group.
  876. Arguments:
  877. Group - Supplies a pointer to the group to destroy.
  878. Return Value:
  879. None.
  880. --*/
  881. {
  882. NetLinkReleaseReference(Group->Link);
  883. MmFreePagedPool(Group);
  884. return;
  885. }
  886. KSTATUS
  887. NetpAcquireSocketMulticastLock (
  888. PNET_SOCKET Socket
  889. )
  890. /*++
  891. Routine Description:
  892. This routine acquires the given socket's multicast lock, allocating it on
  893. the fly if it does not already exist. This is done so most sockets don't
  894. have to allocate the lock, as most sockets don't perform multicast actions.
  895. Arguments:
  896. Socket - Supplies a pointer to the network socket whose multicast lock is
  897. to be acquired.
  898. Return Value:
  899. Status code.
  900. --*/
  901. {
  902. PQUEUED_LOCK NewLock;
  903. PQUEUED_LOCK OldLock;
  904. KSTATUS Status;
  905. //
  906. // If there is no multicast lock. Create one before going any further. This
  907. // is done on the fly so that most sockets don't need to allocate the lock
  908. // resource.
  909. //
  910. if (Socket->MulticastLock == NULL) {
  911. NewLock = KeCreateQueuedLock();
  912. if (NewLock == NULL) {
  913. Status = STATUS_INSUFFICIENT_RESOURCES;
  914. goto AcquireMulticastLockEnd;
  915. }
  916. //
  917. // Try to exchange the lock into place.
  918. //
  919. OldLock = (PQUEUED_LOCK)RtlAtomicCompareExchange(
  920. (PUINTN)&(Socket->MulticastLock),
  921. (UINTN)NewLock,
  922. (UINTN)NULL);
  923. if (OldLock != NULL) {
  924. KeDestroyQueuedLock(NewLock);
  925. }
  926. }
  927. ASSERT(Socket->MulticastLock != NULL);
  928. KeAcquireQueuedLock(Socket->MulticastLock);
  929. Status = STATUS_SUCCESS;
  930. AcquireMulticastLockEnd:
  931. return Status;
  932. }
  933. VOID
  934. NetpReleaseSocketMulticastLock (
  935. PNET_SOCKET Socket
  936. )
  937. /*++
  938. Routine Description:
  939. This routine releases the multicast lock for the given socket.
  940. Arguments:
  941. Socket - Supplies a pointer to a network socket.
  942. Return Value:
  943. None.
  944. --*/
  945. {
  946. ASSERT(Socket->MulticastLock != NULL);
  947. KeReleaseQueuedLock(Socket->MulticastLock);
  948. return;
  949. }
  950. PNET_LINK_MULTICAST_GROUP
  951. NetpFindLinkMulticastGroup (
  952. PNET_LINK Link,
  953. PNET_LINK_ADDRESS_ENTRY LinkAddress,
  954. PNETWORK_ADDRESS MulticastAddress
  955. )
  956. /*++
  957. Routine Description:
  958. This routine finds a multicast group in a link's list of multicast groups.
  959. Arguments:
  960. Link - Supplies a pointer to the link to search.
  961. LinkAddress - Supplies a pointer to the link address entry associated with
  962. the group.
  963. MulticastAddress - Supplies a pointer to the multicast address of the group.
  964. Return Value:
  965. Returns a pointer to a link multicast group on success or NULL on failure.
  966. --*/
  967. {
  968. PLIST_ENTRY CurrentEntry;
  969. PNET_LINK_MULTICAST_GROUP Group;
  970. COMPARISON_RESULT Result;
  971. ASSERT(KeIsQueuedLockHeld(Link->QueuedLock) != FALSE);
  972. CurrentEntry = Link->MulticastGroupList.Next;
  973. while (CurrentEntry != &(Link->MulticastGroupList)) {
  974. Group = LIST_VALUE(CurrentEntry, NET_LINK_MULTICAST_GROUP, ListEntry);
  975. if (Group->LinkAddress == LinkAddress) {
  976. Result = NetCompareNetworkAddresses(&(Group->Address),
  977. MulticastAddress);
  978. if (Result == ComparisonResultSame) {
  979. return Group;
  980. }
  981. }
  982. CurrentEntry = CurrentEntry->Next;
  983. }
  984. return NULL;
  985. }