igmp.c 90 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837
  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. igmp.c
  9. Abstract:
  10. This module implements the Internet Group Management Protocol (IGMP), which
  11. is used to support IPv4 multicast.
  12. Author:
  13. Chris Stevens 23-Feb-2017
  14. Environment:
  15. Kernel
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. //
  21. // Protocol drivers are supposed to be able to stand on their own (ie be able to
  22. // be implemented outside the core net library). For the builtin ones, avoid
  23. // including netcore.h, but still redefine those functions that would otherwise
  24. // generate imports.
  25. //
  26. #define NET_API __DLLEXPORT
  27. #include <minoca/kernel/driver.h>
  28. #include <minoca/net/netdrv.h>
  29. #include <minoca/net/ip4.h>
  30. #include <minoca/net/igmp.h>
  31. //
  32. // --------------------------------------------------------------------- Macros
  33. //
  34. //
  35. // This macro converts IGMPv3 time codes to an actual time value. The time
  36. // units depend on the supplied code being converted.
  37. //
  38. #define IGMP_CONVERT_TIME_CODE_TO_TIME(_ResponseCode) \
  39. (((_ResponseCode) < 128) ? \
  40. (_ResponseCode) : \
  41. ((((_ResponseCode) & 0x0F) | 0x10) << \
  42. ((((_ResponseCode) >> 4) & 0x07) + 3)))
  43. //
  44. // ---------------------------------------------------------------- Definitions
  45. //
  46. //
  47. // Define the allocation tag used by IGMP.
  48. //
  49. #define IGMP_ALLOCATION_TAG 0x706d6749 // 'pmgI'
  50. //
  51. // Define the size of an IGMP IPv4 header. Each packet should include the
  52. // router alert option.
  53. //
  54. #define IGMP_IP4_HEADER_SIZE (sizeof(IP4_HEADER) + sizeof(ULONG))
  55. //
  56. // Store the 32-bit IPv4 router alert option sent with each IGMP packet.
  57. //
  58. #define IGMP_IP4_ROUTER_ALERT_OPTION CPU_TO_NETWORK32(0x94040000)
  59. //
  60. // Define the conversion between query response time units (1/10th of a second)
  61. // and microseconds.
  62. //
  63. #define IGMP_MICROSECONDS_PER_QUERY_TIME_UNIT \
  64. (100 * MICROSECONDS_PER_MILLISECOND)
  65. //
  66. // Define the default max response code for version 1 query messages.
  67. //
  68. #define IGMP_QUERY_V1_MAX_RESPONSE_CODE 100
  69. //
  70. // Define the maximum number of group records that can be included in each
  71. // report.
  72. //
  73. #define IGMP_MAX_GROUP_RECORD_COUNT MAX_USHORT
  74. //
  75. // Define the IPv4 address to which all IGMPv2 leave messages are sent.
  76. //
  77. #define IGMP_ALL_ROUTERS_ADDRESS CPU_TO_NETWORK32(0xE0000002)
  78. //
  79. // Define the IPv4 addres to which all IGMPv3 report messages are sent.
  80. //
  81. #define IGMP_ALL_ROUTERS_ADDRESS_V3 CPU_TO_NETWORK32(0xE0000016)
  82. //
  83. // Define the IGMP message types.
  84. //
  85. #define IGMP_MESSAGE_TYPE_QUERY 0x11
  86. #define IGMP_MESSAGE_TYPE_REPORT_V1 0x12
  87. #define IGMP_MESSAGE_TYPE_REPORT_V2 0x16
  88. #define IGMP_MESSAGE_TYPE_LEAVE_V2 0x17
  89. #define IGMP_MESSAGE_TYPE_REPORT_V3 0x22
  90. //
  91. // Define the IGMP group record types.
  92. //
  93. #define IGMP_GROUP_RECORD_TYPE_MODE_IS_INCLUDE 1
  94. #define IGMP_GROUP_RECORD_TYPE_MODE_IS_EXCLUDE 2
  95. #define IGMP_GROUP_RECORD_TYPE_CHANGE_TO_INCLUDE_MODE 3
  96. #define IGMP_GROUP_RECORD_TYPE_CHANGE_TO_EXCLUDE_MODE 4
  97. #define IGMP_GROUP_RECORD_TYPE_ALLOW_NEW_SOURCES 5
  98. #define IGMP_GROUP_RECORD_TYPE_BLOCK_OLD_SOURCES 6
  99. //
  100. // Define the IGMPv3 query message flag bits.
  101. //
  102. #define IGMP_QUERY_FLAG_SUPPRESS_ROUTER_PROCESSING 0x08
  103. #define IGMP_QUERY_FLAG_ROBUSTNESS_MASK 0x07
  104. #define IGMP_QUERY_FLAG_ROBUSTNESS_SHIFT 0
  105. //
  106. // Define the required number of compatibility modes.
  107. //
  108. #define IGMP_COMPATIBILITY_MODE_COUNT 2
  109. //
  110. // Define the default robustness variable.
  111. //
  112. #define IGMP_DEFAULT_ROBUSTNESS_VARIABLE 2
  113. //
  114. // Define the default query interval, in seconds.
  115. //
  116. #define IGMP_DEFAULT_QUERY_INTERVAL 125
  117. //
  118. // Define the default query response interval, in 1/10 of a second units.
  119. //
  120. #define IGMP_DEFAULT_MAX_RESPONSE_TIME 100
  121. //
  122. // Define the default timeout, in seconds, to wait in the presence of a querier
  123. // with an older version.
  124. //
  125. #define IGMP_DEFAULT_COMPATIBILITY_TIMEOUT 400
  126. //
  127. // Define the default unsolicited report interval in 1/10 of a second units.
  128. //
  129. #define IGMP_DEFAULT_UNSOLICITED_REPORT_INTERVAL 10
  130. //
  131. // Define the set of multicast group flags.
  132. //
  133. #define IGMP_MULTICAST_GROUP_FLAG_LAST_REPORT 0x00000001
  134. #define IGMP_MULTICAST_GROUP_FLAG_STATE_CHANGE 0x00000002
  135. #define IGMP_MULTICAST_GROUP_FLAG_LEAVE_SENT 0x00000004
  136. //
  137. // ------------------------------------------------------ Data Type Definitions
  138. //
  139. typedef enum _IGMP_VERSION {
  140. IgmpVersion1,
  141. IgmpVersion2,
  142. IgmpVersion3
  143. } IGMP_VERSION, *PIGMP_VERSION;
  144. /*++
  145. Structure Description:
  146. This structure define the header common to all IGMP packets.
  147. Members:
  148. Type - Stores the IGMP message type.
  149. MaxResponseCode - Stores the encoded maximum response time for query
  150. messages.
  151. Checksum - Stores the 16 bit one's complement of the one's complement
  152. sum of all 16 bit words in the IGMP message payload.
  153. --*/
  154. #pragma pack(push, 1)
  155. typedef struct _IGMP_HEADER {
  156. UCHAR Type;
  157. UCHAR MaxResponseCode;
  158. USHORT Checksum;
  159. } PACKED IGMP_HEADER, *PIGMP_HEADER;
  160. /*++
  161. Structure Description:
  162. This structure defines a generic IGMP message. It is the same structure for
  163. IGMPv1 and IGMPv2 queries, reports, and leave messages.
  164. Members:
  165. Header - Stores the common IGMP message header.
  166. GroupAddress - Stores the IPv4 address of the group being queried,
  167. reported or left.
  168. --*/
  169. typedef struct _IGMP_MESSAGE {
  170. IGMP_HEADER Header;
  171. ULONG GroupAddress;
  172. } PACKED IGMP_MESSAGE, *PIGMP_MESSAGE;
  173. /*++
  174. Structure Description:
  175. This structure defines a IGMPv3 query message. At the end of the structure
  176. is an array of source IPv4 addresses.
  177. Members:
  178. Message - Stores the common IGMP message that starts the IGMPv3 query.
  179. Flags - Stores a bitmask of IGMPv3 query flags. See IGMP_QUERY_FLAG_* for
  180. definitions.
  181. QueryIntervalCode - Stores the encoded query interval of the router.
  182. SourceAddressCount - Stores the number of source address entries that
  183. immediately follow this structure.
  184. --*/
  185. typedef struct _IGMP_QUERY_V3 {
  186. IGMP_MESSAGE Message;
  187. UCHAR Flags;
  188. UCHAR QueryIntervalCode;
  189. USHORT SourceAddressCount;
  190. } PACKED IGMP_QUERY_V3, *PIGMP_QUERY_V3;
  191. /*++
  192. Structure Description:
  193. This structure defines an IGMPv3 group record.
  194. Members:
  195. Type - Stores the group record type.
  196. DataLength - Stores the length of auxiliary data, in 32-bit words, that
  197. starts at the end of the source address array.
  198. SourceAddressCount - Stores the number of source address entries in the
  199. array that starts at the end of this structure.
  200. MulticastAddress - Stores the multicast address of the group.
  201. --*/
  202. typedef struct _IGMP_GROUP_RECORD_V3 {
  203. UCHAR Type;
  204. UCHAR DataLength;
  205. USHORT SourceAddressCount;
  206. ULONG MulticastAddress;
  207. } PACKED IGMP_GROUP_RECORD_V3, *PIGMP_GROUP_RECORD_V3;
  208. /*++
  209. Structure Description:
  210. This structure defines the IGMPv3 report message.
  211. Members:
  212. Header - Stores the common IGMP header.
  213. Reserved - Stores two reserved bytes.
  214. GroupRecordCount - Stores the number of group records stored in the array
  215. that begins immediately after this structure.
  216. --*/
  217. typedef struct _IGMP_REPORT_V3 {
  218. IGMP_HEADER Header;
  219. USHORT Reserved;
  220. USHORT GroupRecordCount;
  221. } PACKED IGMP_REPORT_V3, *PIGMP_REPORT_V3;
  222. #pragma pack(pop)
  223. /*++
  224. Structure Description:
  225. This structure defines an generic IGMP timer that kicks off a DPC, which
  226. then queues a work item.
  227. Members:
  228. Timer - Stores a pointer to the internal timer.
  229. Dpc - Stores a pointer to the DPC that executes when the timer expires.
  230. WorkItem - Stores a pointer to the work item that is scheduled by the DPC.
  231. --*/
  232. typedef struct _IGMP_TIMER {
  233. PKTIMER Timer;
  234. PDPC Dpc;
  235. PWORK_ITEM WorkItem;
  236. } IGMP_TIMER, *PIGMP_TIMER;
  237. /*++
  238. Structure Description:
  239. This structure defines an IGMP link.
  240. Members:
  241. Node - Stores the link's entry into the global tree of IGMP links.
  242. ReferenceCount - Stores the reference count on the structure.
  243. Link - Stores a pointer to the network link to which this IGMP link is
  244. bound.
  245. LinkAddress - Stores a pointer to the network link address entry with which
  246. the IGMP link is associated.
  247. MaxPacketSize - Stores the maximum IGMP packet size that can be sent over
  248. the link.
  249. RobustnessVariable - Stores the multicast router's robustness variable.
  250. QueryInterval - Stores the multicat router's query interval, in seconds.
  251. MaxResponseTime - Stores the maximum response time for a IGMP report, in
  252. units of 1/10 seconds.
  253. Lock - Stores a queued lock that protects the IGMP link.
  254. CompatibilityMode - Stores the current compatibility mode of the IGMP link.
  255. This is based on the type of query messages received on the network.
  256. CompatibilityTimer - Stores an array of timers for each of the older
  257. versions of IGMP that must be supported.
  258. ReportTimer - Stores the report timer used for responding to generic
  259. queries.
  260. GroupCount - Stores the number of multicast groups that are associated
  261. with the link and should be reported in a total link report.
  262. MulticastGroupList - Stores the list of the multicast group structures
  263. associated with the link.
  264. --*/
  265. typedef struct _IGMP_LINK {
  266. RED_BLACK_TREE_NODE Node;
  267. volatile ULONG ReferenceCount;
  268. PNET_LINK Link;
  269. PNET_LINK_ADDRESS_ENTRY LinkAddress;
  270. ULONG MaxPacketSize;
  271. ULONG RobustnessVariable;
  272. ULONG QueryInterval;
  273. ULONG MaxResponseTime;
  274. PQUEUED_LOCK Lock;
  275. volatile IGMP_VERSION CompatibilityMode;
  276. IGMP_TIMER CompatibilityTimer[IGMP_COMPATIBILITY_MODE_COUNT];
  277. IGMP_TIMER ReportTimer;
  278. ULONG GroupCount;
  279. LIST_ENTRY MulticastGroupList;
  280. } IGMP_LINK, *PIGMP_LINK;
  281. /*++
  282. Structure Description:
  283. This structure defines an IGMP multicast group.
  284. Members:
  285. ListEntry - Stores the group's entry into its parent's list of multicast
  286. groups.
  287. ReferenceCount - Stores the reference count on the structure.
  288. SendCount - Stores the number of pending report or leave messages to be
  289. sending. This number should always be less than or equal to the
  290. robustness value. Updates are protected by the IGMP link's queued lock.
  291. Flags - Stores a bitmask of multicast group flags. See
  292. IGMP_MULTICAST_GROUP_FLAG_* for definitions. Updates are protected by
  293. the IGMP link's queued lock.
  294. JoinCount - Stores the number of times a join request has been made for
  295. this multicast group. This is protected by the IGMP link's queued lock.
  296. Address - Stores the IPv4 multicast address of the group.
  297. IgmpLink - Stores a pointer to the IGMP link to which this group belongs.
  298. Timer - Stores the timer used to schedule delayed and repeated IGMP report
  299. and leave messages.
  300. --*/
  301. typedef struct _IGMP_MULTICAST_GROUP {
  302. LIST_ENTRY ListEntry;
  303. volatile ULONG ReferenceCount;
  304. ULONG SendCount;
  305. ULONG Flags;
  306. ULONG JoinCount;
  307. ULONG Address;
  308. PIGMP_LINK IgmpLink;
  309. IGMP_TIMER Timer;
  310. } IGMP_MULTICAST_GROUP, *PIGMP_MULTICAST_GROUP;
  311. //
  312. // ----------------------------------------------- Internal Function Prototypes
  313. //
  314. KSTATUS
  315. NetpIgmpCreateSocket (
  316. PNET_PROTOCOL_ENTRY ProtocolEntry,
  317. PNET_NETWORK_ENTRY NetworkEntry,
  318. ULONG NetworkProtocol,
  319. PNET_SOCKET *NewSocket,
  320. ULONG Phase
  321. );
  322. VOID
  323. NetpIgmpDestroySocket (
  324. PNET_SOCKET Socket
  325. );
  326. KSTATUS
  327. NetpIgmpBindToAddress (
  328. PNET_SOCKET Socket,
  329. PNET_LINK Link,
  330. PNETWORK_ADDRESS Address
  331. );
  332. KSTATUS
  333. NetpIgmpListen (
  334. PNET_SOCKET Socket
  335. );
  336. KSTATUS
  337. NetpIgmpAccept (
  338. PNET_SOCKET Socket,
  339. PIO_HANDLE *NewConnectionSocket,
  340. PNETWORK_ADDRESS RemoteAddress
  341. );
  342. KSTATUS
  343. NetpIgmpConnect (
  344. PNET_SOCKET Socket,
  345. PNETWORK_ADDRESS Address
  346. );
  347. KSTATUS
  348. NetpIgmpClose (
  349. PNET_SOCKET Socket
  350. );
  351. KSTATUS
  352. NetpIgmpShutdown (
  353. PNET_SOCKET Socket,
  354. ULONG ShutdownType
  355. );
  356. KSTATUS
  357. NetpIgmpSend (
  358. BOOL FromKernelMode,
  359. PNET_SOCKET Socket,
  360. PSOCKET_IO_PARAMETERS Parameters,
  361. PIO_BUFFER IoBuffer
  362. );
  363. VOID
  364. NetpIgmpProcessReceivedData (
  365. PNET_RECEIVE_CONTEXT ReceiveContext
  366. );
  367. KSTATUS
  368. NetpIgmpProcessReceivedSocketData (
  369. PNET_SOCKET Socket,
  370. PNET_RECEIVE_CONTEXT ReceiveContext
  371. );
  372. KSTATUS
  373. NetpIgmpReceive (
  374. BOOL FromKernelMode,
  375. PNET_SOCKET Socket,
  376. PSOCKET_IO_PARAMETERS Parameters,
  377. PIO_BUFFER IoBuffer
  378. );
  379. KSTATUS
  380. NetpIgmpGetSetInformation (
  381. PNET_SOCKET Socket,
  382. SOCKET_INFORMATION_TYPE InformationType,
  383. UINTN SocketOption,
  384. PVOID Data,
  385. PUINTN DataSize,
  386. BOOL Set
  387. );
  388. KSTATUS
  389. NetpIgmpUserControl (
  390. PNET_SOCKET Socket,
  391. ULONG CodeNumber,
  392. BOOL FromKernelMode,
  393. PVOID ContextBuffer,
  394. UINTN ContextBufferSize
  395. );
  396. KSTATUS
  397. NetpIgmpJoinMulticastGroup (
  398. PNET_NETWORK_MULTICAST_REQUEST Request
  399. );
  400. KSTATUS
  401. NetpIgmpLeaveMulticastGroup (
  402. PNET_NETWORK_MULTICAST_REQUEST Request
  403. );
  404. VOID
  405. NetpIgmpProcessQuery (
  406. PIGMP_LINK Link,
  407. PNET_PACKET_BUFFER Packet,
  408. PNETWORK_ADDRESS SourceAddress,
  409. PNETWORK_ADDRESS DestinationAddress
  410. );
  411. VOID
  412. NetpIgmpProcessReport (
  413. PIGMP_LINK Link,
  414. PNET_PACKET_BUFFER Packet,
  415. PNETWORK_ADDRESS SourceAddress,
  416. PNETWORK_ADDRESS DestinationAddress
  417. );
  418. VOID
  419. NetpIgmpQueueReportTimer (
  420. PIGMP_TIMER ReportTimer,
  421. ULONGLONG StartTime,
  422. ULONG MaxResponseTime
  423. );
  424. VOID
  425. NetpIgmpTimerDpcRoutine (
  426. PDPC Dpc
  427. );
  428. VOID
  429. NetpIgmpGroupTimeoutWorker (
  430. PVOID Parameter
  431. );
  432. VOID
  433. NetpIgmpLinkReportTimeoutWorker (
  434. PVOID Parameter
  435. );
  436. VOID
  437. NetpIgmpLinkCompatibilityTimeoutWorker (
  438. PVOID Parameter
  439. );
  440. VOID
  441. NetpIgmpQueueCompatibilityTimer (
  442. PIGMP_LINK IgmpLink,
  443. IGMP_VERSION CompatibilityMode
  444. );
  445. VOID
  446. NetpIgmpUpdateCompatibilityMode (
  447. PIGMP_LINK IgmpLink
  448. );
  449. VOID
  450. NetpIgmpSendGroupReport (
  451. PIGMP_MULTICAST_GROUP Group
  452. );
  453. VOID
  454. NetpIgmpSendLinkReport (
  455. PIGMP_LINK Link
  456. );
  457. VOID
  458. NetpIgmpSendGroupLeave (
  459. PIGMP_MULTICAST_GROUP Group
  460. );
  461. VOID
  462. NetpIgmpSendPackets (
  463. PIGMP_LINK IgmpLink,
  464. PNETWORK_ADDRESS Destination,
  465. PNET_PACKET_LIST PacketList
  466. );
  467. PIGMP_LINK
  468. NetpIgmpCreateOrLookupLink (
  469. PNET_LINK Link,
  470. PNET_LINK_ADDRESS_ENTRY LinkAddress
  471. );
  472. VOID
  473. NetpIgmpDestroyLink (
  474. PIGMP_LINK IgmpLink
  475. );
  476. PIGMP_LINK
  477. NetpIgmpLookupLink (
  478. PNET_LINK Link
  479. );
  480. VOID
  481. NetpIgmpLinkAddReference (
  482. PIGMP_LINK IgmpLink
  483. );
  484. VOID
  485. NetpIgmpLinkReleaseReference (
  486. PIGMP_LINK IgmpLink
  487. );
  488. COMPARISON_RESULT
  489. NetpIgmpCompareLinkEntries (
  490. PRED_BLACK_TREE Tree,
  491. PRED_BLACK_TREE_NODE FirstNode,
  492. PRED_BLACK_TREE_NODE SecondNode
  493. );
  494. PIGMP_MULTICAST_GROUP
  495. NetpIgmpCreateGroup (
  496. PIGMP_LINK IgmpLink,
  497. PIP4_ADDRESS GroupAddress
  498. );
  499. VOID
  500. NetpIgmpDestroyGroup (
  501. PIGMP_MULTICAST_GROUP Group
  502. );
  503. PIGMP_MULTICAST_GROUP
  504. NetpIgmpLookupGroup (
  505. PIGMP_LINK IgmpLink,
  506. PIP4_ADDRESS GroupAddress
  507. );
  508. VOID
  509. NetpIgmpGroupAddReference (
  510. PIGMP_MULTICAST_GROUP Group
  511. );
  512. VOID
  513. NetpIgmpGroupReleaseReference (
  514. PIGMP_MULTICAST_GROUP Group
  515. );
  516. KSTATUS
  517. NetpIgmpInitializeTimer (
  518. PIGMP_TIMER Timer,
  519. PWORK_ITEM_ROUTINE WorkRoutine,
  520. PVOID WorkParameter
  521. );
  522. VOID
  523. NetpIgmpDestroyTimer (
  524. PIGMP_TIMER Timer
  525. );
  526. BOOL
  527. NetpIgmpIsReportableAddress (
  528. ULONG Address
  529. );
  530. //
  531. // -------------------------------------------------------------------- Globals
  532. //
  533. NET_PROTOCOL_ENTRY NetIgmpProtocol = {
  534. {NULL, NULL},
  535. NetSocketDatagram,
  536. SOCKET_INTERNET_PROTOCOL_IGMP,
  537. 0,
  538. NULL,
  539. NULL,
  540. {{0}, {0}, {0}},
  541. {
  542. NetpIgmpCreateSocket,
  543. NetpIgmpDestroySocket,
  544. NetpIgmpBindToAddress,
  545. NetpIgmpListen,
  546. NetpIgmpAccept,
  547. NetpIgmpConnect,
  548. NetpIgmpClose,
  549. NetpIgmpShutdown,
  550. NetpIgmpSend,
  551. NetpIgmpProcessReceivedData,
  552. NetpIgmpProcessReceivedSocketData,
  553. NetpIgmpReceive,
  554. NetpIgmpGetSetInformation,
  555. NetpIgmpUserControl
  556. }
  557. };
  558. //
  559. // Stores a global tree of net links that are signed up for multicast groups
  560. // via IGMP.
  561. //
  562. RED_BLACK_TREE NetIgmpLinkTree;
  563. PSHARED_EXCLUSIVE_LOCK NetIgmpLinkLock;
  564. //
  565. // ------------------------------------------------------------------ Functions
  566. //
  567. VOID
  568. NetpIgmpInitialize (
  569. VOID
  570. )
  571. /*++
  572. Routine Description:
  573. This routine initializes support for the IGMP protocol.
  574. Arguments:
  575. None.
  576. Return Value:
  577. None.
  578. --*/
  579. {
  580. KSTATUS Status;
  581. RtlRedBlackTreeInitialize(&NetIgmpLinkTree, 0, NetpIgmpCompareLinkEntries);
  582. NetIgmpLinkLock = KeCreateSharedExclusiveLock();
  583. if (NetIgmpLinkLock == NULL) {
  584. ASSERT(FALSE);
  585. return;
  586. }
  587. //
  588. // Register the IGMP socket handlers with the core networking library.
  589. //
  590. Status = NetRegisterProtocol(&NetIgmpProtocol, NULL);
  591. if (!KSUCCESS(Status)) {
  592. ASSERT(FALSE);
  593. }
  594. return;
  595. }
  596. KSTATUS
  597. NetpIgmpCreateSocket (
  598. PNET_PROTOCOL_ENTRY ProtocolEntry,
  599. PNET_NETWORK_ENTRY NetworkEntry,
  600. ULONG NetworkProtocol,
  601. PNET_SOCKET *NewSocket,
  602. ULONG Phase
  603. )
  604. /*++
  605. Routine Description:
  606. This routine allocates resources associated with a new socket. The protocol
  607. driver is responsible for allocating the structure (with additional length
  608. for any of its context). The core networking library will fill in the
  609. common header when this routine returns.
  610. Arguments:
  611. ProtocolEntry - Supplies a pointer to the protocol information.
  612. NetworkEntry - Supplies a pointer to the network information.
  613. NetworkProtocol - Supplies the raw protocol value for this socket used on
  614. the network. This value is network specific.
  615. NewSocket - Supplies a pointer where a pointer to a newly allocated
  616. socket structure will be returned. The caller is responsible for
  617. allocating the socket (and potentially a larger structure for its own
  618. context). The core network library will fill in the standard socket
  619. structure after this routine returns. In phase 1, this will contain
  620. a pointer to the socket allocated during phase 0.
  621. Phase - Supplies the socket creation phase. Phase 0 is the allocation phase
  622. and phase 1 is the advanced initialization phase, which is invoked
  623. after net core is done filling out common portions of the socket
  624. structure.
  625. Return Value:
  626. Status code.
  627. --*/
  628. {
  629. return STATUS_NOT_SUPPORTED_BY_PROTOCOL;
  630. }
  631. VOID
  632. NetpIgmpDestroySocket (
  633. PNET_SOCKET Socket
  634. )
  635. /*++
  636. Routine Description:
  637. This routine destroys resources associated with an open socket, officially
  638. marking the end of the kernel and core networking library's knowledge of
  639. this structure.
  640. Arguments:
  641. Socket - Supplies a pointer to the socket to destroy. The core networking
  642. library will have already destroyed any resources inside the common
  643. header, the protocol should not reach through any pointers inside the
  644. socket header except the protocol and network entries.
  645. Return Value:
  646. None. This routine is responsible for freeing the memory associated with
  647. the socket structure itself.
  648. --*/
  649. {
  650. return;
  651. }
  652. KSTATUS
  653. NetpIgmpBindToAddress (
  654. PNET_SOCKET Socket,
  655. PNET_LINK Link,
  656. PNETWORK_ADDRESS Address
  657. )
  658. /*++
  659. Routine Description:
  660. This routine binds the given socket to the specified network address.
  661. Usually this is a no-op for the protocol, it's simply responsible for
  662. passing the request down to the network layer.
  663. Arguments:
  664. Socket - Supplies a pointer to the socket to bind.
  665. Link - Supplies an optional pointer to a link to bind to.
  666. Address - Supplies a pointer to the address to bind the socket to.
  667. Return Value:
  668. Status code.
  669. --*/
  670. {
  671. return STATUS_NOT_SUPPORTED_BY_PROTOCOL;
  672. }
  673. KSTATUS
  674. NetpIgmpListen (
  675. PNET_SOCKET Socket
  676. )
  677. /*++
  678. Routine Description:
  679. This routine adds a bound socket to the list of listening sockets,
  680. officially allowing clients to attempt to connect to it.
  681. Arguments:
  682. Socket - Supplies a pointer to the socket to mark as listning.
  683. Return Value:
  684. Status code.
  685. --*/
  686. {
  687. return STATUS_NOT_SUPPORTED_BY_PROTOCOL;
  688. }
  689. KSTATUS
  690. NetpIgmpAccept (
  691. PNET_SOCKET Socket,
  692. PIO_HANDLE *NewConnectionSocket,
  693. PNETWORK_ADDRESS RemoteAddress
  694. )
  695. /*++
  696. Routine Description:
  697. This routine accepts an incoming connection on a listening connection-based
  698. socket.
  699. Arguments:
  700. Socket - Supplies a pointer to the socket to accept a connection from.
  701. NewConnectionSocket - Supplies a pointer where a new socket will be
  702. returned that represents the accepted connection with the remote
  703. host.
  704. RemoteAddress - Supplies a pointer where the address of the connected
  705. remote host will be returned.
  706. Return Value:
  707. Status code.
  708. --*/
  709. {
  710. return STATUS_NOT_SUPPORTED_BY_PROTOCOL;
  711. }
  712. KSTATUS
  713. NetpIgmpConnect (
  714. PNET_SOCKET Socket,
  715. PNETWORK_ADDRESS Address
  716. )
  717. /*++
  718. Routine Description:
  719. This routine attempts to make an outgoing connection to a server.
  720. Arguments:
  721. Socket - Supplies a pointer to the socket to use for the connection.
  722. Address - Supplies a pointer to the address to connect to.
  723. Return Value:
  724. Status code.
  725. --*/
  726. {
  727. return STATUS_NOT_SUPPORTED_BY_PROTOCOL;
  728. }
  729. KSTATUS
  730. NetpIgmpClose (
  731. PNET_SOCKET Socket
  732. )
  733. /*++
  734. Routine Description:
  735. This routine closes a socket connection.
  736. Arguments:
  737. Socket - Supplies a pointer to the socket to shut down.
  738. Return Value:
  739. Status code.
  740. --*/
  741. {
  742. return STATUS_NOT_SUPPORTED_BY_PROTOCOL;
  743. }
  744. KSTATUS
  745. NetpIgmpShutdown (
  746. PNET_SOCKET Socket,
  747. ULONG ShutdownType
  748. )
  749. /*++
  750. Routine Description:
  751. This routine shuts down communication with a given socket.
  752. Arguments:
  753. Socket - Supplies a pointer to the socket.
  754. ShutdownType - Supplies the shutdown type to perform. See the
  755. SOCKET_SHUTDOWN_* definitions.
  756. Return Value:
  757. Status code.
  758. --*/
  759. {
  760. return STATUS_NOT_SUPPORTED_BY_PROTOCOL;
  761. }
  762. KSTATUS
  763. NetpIgmpSend (
  764. BOOL FromKernelMode,
  765. PNET_SOCKET Socket,
  766. PSOCKET_IO_PARAMETERS Parameters,
  767. PIO_BUFFER IoBuffer
  768. )
  769. /*++
  770. Routine Description:
  771. This routine sends the given data buffer through the network using a
  772. specific protocol.
  773. Arguments:
  774. FromKernelMode - Supplies a boolean indicating whether the request is
  775. coming from kernel mode (TRUE) or user mode (FALSE).
  776. Socket - Supplies a pointer to the socket to send the data to.
  777. Parameters - Supplies a pointer to the socket I/O parameters. This will
  778. always be a kernel mode pointer.
  779. IoBuffer - Supplies a pointer to the I/O buffer containing the data to
  780. send.
  781. Return Value:
  782. Status code.
  783. --*/
  784. {
  785. return STATUS_NOT_SUPPORTED_BY_PROTOCOL;
  786. }
  787. VOID
  788. NetpIgmpProcessReceivedData (
  789. PNET_RECEIVE_CONTEXT ReceiveContext
  790. )
  791. /*++
  792. Routine Description:
  793. This routine is called to process a received packet.
  794. Arguments:
  795. ReceiveContext - Supplies a pointer to the receive context that stores the
  796. link, packet, network, protocol, and source and destination addresses.
  797. Return Value:
  798. None. When the function returns, the memory associated with the packet may
  799. be reclaimed and reused.
  800. --*/
  801. {
  802. USHORT ComputedChecksum;
  803. PIGMP_HEADER Header;
  804. PIGMP_LINK IgmpLink;
  805. ULONG Length;
  806. PNET_PACKET_BUFFER Packet;
  807. ASSERT(KeGetRunLevel() == RunLevelLow);
  808. //
  809. // Do nothing if this link is not registered with IGMP. The packet is
  810. // likely old.
  811. //
  812. IgmpLink = NetpIgmpLookupLink(ReceiveContext->Link);
  813. if (IgmpLink == NULL) {
  814. goto IgmpProcessReceivedDataEnd;
  815. }
  816. //
  817. // Make sure there is at least the common header to read.
  818. //
  819. Packet = ReceiveContext->Packet;
  820. Header = (PIGMP_HEADER)(Packet->Buffer + Packet->DataOffset);
  821. Length = Packet->FooterOffset - Packet->DataOffset;
  822. if (Length < sizeof(IGMP_HEADER)) {
  823. RtlDebugPrint("IGMP: Invalid length of %d. Expected at least %d "
  824. "bytes.\n",
  825. Length,
  826. sizeof(IGMP_HEADER));
  827. goto IgmpProcessReceivedDataEnd;
  828. }
  829. //
  830. // Validate the IGMP checksum.
  831. //
  832. ComputedChecksum = NetChecksumData((PVOID)Header, Length);
  833. if (ComputedChecksum != 0) {
  834. RtlDebugPrint("IGMP: Invalid checksum. Computed checksum: 0x%04x, "
  835. "should have been zero.\n",
  836. ComputedChecksum);
  837. goto IgmpProcessReceivedDataEnd;
  838. }
  839. //
  840. // Handle the IGMP packet based on the type field.
  841. //
  842. switch (Header->Type) {
  843. case IGMP_MESSAGE_TYPE_QUERY:
  844. NetpIgmpProcessQuery(IgmpLink,
  845. Packet,
  846. ReceiveContext->Source,
  847. ReceiveContext->Destination);
  848. break;
  849. case IGMP_MESSAGE_TYPE_REPORT_V1:
  850. case IGMP_MESSAGE_TYPE_REPORT_V2:
  851. NetpIgmpProcessReport(IgmpLink,
  852. Packet,
  853. ReceiveContext->Source,
  854. ReceiveContext->Destination);
  855. break;
  856. //
  857. // IGMPv3 reports are ignored.
  858. //
  859. case IGMP_MESSAGE_TYPE_REPORT_V3:
  860. break;
  861. //
  862. // A leave message should only be handled by a router.
  863. //
  864. case IGMP_MESSAGE_TYPE_LEAVE_V2:
  865. break;
  866. default:
  867. break;
  868. }
  869. IgmpProcessReceivedDataEnd:
  870. if (IgmpLink != NULL) {
  871. NetpIgmpLinkReleaseReference(IgmpLink);
  872. }
  873. return;
  874. }
  875. KSTATUS
  876. NetpIgmpProcessReceivedSocketData (
  877. PNET_SOCKET Socket,
  878. PNET_RECEIVE_CONTEXT ReceiveContext
  879. )
  880. /*++
  881. Routine Description:
  882. This routine is called for a particular socket to process a received packet
  883. that was sent to it.
  884. Arguments:
  885. Socket - Supplies a pointer to the socket that received the packet.
  886. ReceiveContext - Supplies a pointer to the receive context that stores the
  887. link, packet, network, protocol, and source and destination addresses.
  888. Return Value:
  889. Status code.
  890. --*/
  891. {
  892. return STATUS_NOT_SUPPORTED_BY_PROTOCOL;
  893. }
  894. KSTATUS
  895. NetpIgmpReceive (
  896. BOOL FromKernelMode,
  897. PNET_SOCKET Socket,
  898. PSOCKET_IO_PARAMETERS Parameters,
  899. PIO_BUFFER IoBuffer
  900. )
  901. /*++
  902. Routine Description:
  903. This routine is called by the user to receive data from the socket on a
  904. particular protocol.
  905. Arguments:
  906. FromKernelMode - Supplies a boolean indicating whether the request is
  907. coming from kernel mode (TRUE) or user mode (FALSE).
  908. Socket - Supplies a pointer to the socket to receive data from.
  909. Parameters - Supplies a pointer to the socket I/O parameters.
  910. IoBuffer - Supplies a pointer to the I/O buffer where the received data
  911. will be returned.
  912. Return Value:
  913. STATUS_SUCCESS if any bytes were read.
  914. STATUS_TIMEOUT if the request timed out.
  915. STATUS_BUFFER_TOO_SMALL if the incoming datagram was too large for the
  916. buffer. The remainder of the datagram is discarded in this case.
  917. Other error codes on other failures.
  918. --*/
  919. {
  920. return STATUS_NOT_SUPPORTED_BY_PROTOCOL;
  921. }
  922. KSTATUS
  923. NetpIgmpGetSetInformation (
  924. PNET_SOCKET Socket,
  925. SOCKET_INFORMATION_TYPE InformationType,
  926. UINTN Option,
  927. PVOID Data,
  928. PUINTN DataSize,
  929. BOOL Set
  930. )
  931. /*++
  932. Routine Description:
  933. This routine gets or sets properties of the given socket.
  934. Arguments:
  935. Socket - Supplies a pointer to the socket to get or set information for.
  936. InformationType - Supplies the socket information type category to which
  937. specified option belongs.
  938. Option - Supplies the option to get or set, which is specific to the
  939. information type. The type of this value is generally
  940. SOCKET_<information_type>_OPTION.
  941. Data - Supplies a pointer to the data buffer where the data is either
  942. returned for a get operation or given for a set operation.
  943. DataSize - Supplies a pointer that on input constains the size of the data
  944. buffer. On output, this contains the required size of the data buffer.
  945. Set - Supplies a boolean indicating if this is a get operation (FALSE) or
  946. a set operation (TRUE).
  947. Return Value:
  948. STATUS_SUCCESS on success.
  949. STATUS_INVALID_PARAMETER if the information type is incorrect.
  950. STATUS_BUFFER_TOO_SMALL if the data buffer is too small to receive the
  951. requested option.
  952. STATUS_NOT_SUPPORTED_BY_PROTOCOL if the socket option is not supported by
  953. the socket.
  954. STATUS_NOT_HANDLED if the protocol does not override the default behavior
  955. for a basic socket option.
  956. --*/
  957. {
  958. SOCKET_IGMP_OPTION IgmpOption;
  959. PIP4_ADDRESS MulticastAddress;
  960. PNET_NETWORK_MULTICAST_REQUEST MulticastRequest;
  961. UINTN RequiredSize;
  962. PVOID Source;
  963. KSTATUS Status;
  964. if (InformationType != SocketInformationIgmp) {
  965. Status = STATUS_INVALID_PARAMETER;
  966. goto IgmpGetSetInformationEnd;
  967. }
  968. RequiredSize = 0;
  969. Source = NULL;
  970. Status = STATUS_SUCCESS;
  971. IgmpOption = (SOCKET_IGMP_OPTION)Option;
  972. switch (IgmpOption) {
  973. case SocketIgmpOptionJoinMulticastGroup:
  974. case SocketIgmpOptionLeaveMulticastGroup:
  975. if (Set == FALSE) {
  976. Status = STATUS_NOT_SUPPORTED_BY_PROTOCOL;
  977. break;
  978. }
  979. RequiredSize = sizeof(NET_NETWORK_MULTICAST_REQUEST);
  980. if (*DataSize < RequiredSize) {
  981. *DataSize = RequiredSize;
  982. Status = STATUS_BUFFER_TOO_SMALL;
  983. break;
  984. }
  985. MulticastRequest = (PNET_NETWORK_MULTICAST_REQUEST)Data;
  986. MulticastAddress = (PIP4_ADDRESS)MulticastRequest->MulticastAddress;
  987. if ((MulticastAddress->Domain != NetDomainIp4) ||
  988. (!IP4_IS_MULTICAST_ADDRESS(MulticastAddress->Address))) {
  989. Status = STATUS_INVALID_PARAMETER;
  990. break;
  991. }
  992. if (IgmpOption == SocketIgmpOptionJoinMulticastGroup) {
  993. Status = NetpIgmpJoinMulticastGroup(MulticastRequest);
  994. } else {
  995. Status = NetpIgmpLeaveMulticastGroup(MulticastRequest);
  996. }
  997. break;
  998. default:
  999. Status = STATUS_NOT_SUPPORTED_BY_PROTOCOL;
  1000. break;
  1001. }
  1002. if (!KSUCCESS(Status)) {
  1003. goto IgmpGetSetInformationEnd;
  1004. }
  1005. //
  1006. // Truncate all copies for get requests down to the required size and
  1007. // always return the required size on set requests.
  1008. //
  1009. if (*DataSize > RequiredSize) {
  1010. *DataSize = RequiredSize;
  1011. }
  1012. //
  1013. // For get requests, copy the gathered information to the supplied data
  1014. // buffer.
  1015. //
  1016. if (Set == FALSE) {
  1017. ASSERT(Source != NULL);
  1018. RtlCopyMemory(Data, Source, *DataSize);
  1019. //
  1020. // If the copy truncated the data, report that the given buffer was too
  1021. // small. The caller can choose to ignore this if the truncated data is
  1022. // enough.
  1023. //
  1024. if (*DataSize < RequiredSize) {
  1025. *DataSize = RequiredSize;
  1026. Status = STATUS_BUFFER_TOO_SMALL;
  1027. goto IgmpGetSetInformationEnd;
  1028. }
  1029. }
  1030. IgmpGetSetInformationEnd:
  1031. return Status;
  1032. }
  1033. KSTATUS
  1034. NetpIgmpUserControl (
  1035. PNET_SOCKET Socket,
  1036. ULONG CodeNumber,
  1037. BOOL FromKernelMode,
  1038. PVOID ContextBuffer,
  1039. UINTN ContextBufferSize
  1040. )
  1041. /*++
  1042. Routine Description:
  1043. This routine handles user control requests destined for a socket.
  1044. Arguments:
  1045. Socket - Supplies a pointer to the socket.
  1046. CodeNumber - Supplies the minor code of the request.
  1047. FromKernelMode - Supplies a boolean indicating whether or not this request
  1048. (and the buffer associated with it) originates from user mode (FALSE)
  1049. or kernel mode (TRUE).
  1050. ContextBuffer - Supplies a pointer to the context buffer allocated by the
  1051. caller for the request.
  1052. ContextBufferSize - Supplies the size of the supplied context buffer.
  1053. Return Value:
  1054. Status code.
  1055. --*/
  1056. {
  1057. return STATUS_NOT_SUPPORTED;
  1058. }
  1059. //
  1060. // --------------------------------------------------------- Internal Functions
  1061. //
  1062. KSTATUS
  1063. NetpIgmpJoinMulticastGroup (
  1064. PNET_NETWORK_MULTICAST_REQUEST Request
  1065. )
  1066. /*++
  1067. Routine Description:
  1068. This routine joins the multicast group on the network link provided in the
  1069. request. If this is the first request to join the supplied multicast group
  1070. on the specified link, then an IGMP report is sent out over the network.
  1071. Arguments:
  1072. Request - Supplies a pointer to a multicast request, which includes the
  1073. address of the group to join and the network link on which to join the
  1074. group.
  1075. Return Value:
  1076. Status code.
  1077. --*/
  1078. {
  1079. PIGMP_MULTICAST_GROUP Group;
  1080. PIP4_ADDRESS GroupAddress;
  1081. PIGMP_LINK IgmpLink;
  1082. BOOL LinkLockHeld;
  1083. PIGMP_MULTICAST_GROUP NewGroup;
  1084. KSTATUS Status;
  1085. Group = NULL;
  1086. LinkLockHeld = FALSE;
  1087. GroupAddress = (PIP4_ADDRESS)Request->MulticastAddress;
  1088. NewGroup = NULL;
  1089. //
  1090. // If the group never needs to be reported, don't bother to record it at
  1091. // this layer. Netcore already has a record of it.
  1092. //
  1093. if (NetpIgmpIsReportableAddress(GroupAddress->Address) == FALSE) {
  1094. return STATUS_SUCCESS;
  1095. }
  1096. //
  1097. // Test to see if there is an IGMP link for the given network link,
  1098. // creating one if the lookup fails.
  1099. //
  1100. IgmpLink = NetpIgmpLookupLink(Request->Link);
  1101. if (IgmpLink == NULL) {
  1102. IgmpLink = NetpIgmpCreateOrLookupLink(Request->Link,
  1103. Request->LinkAddress);
  1104. if (IgmpLink == NULL) {
  1105. Status = STATUS_INSUFFICIENT_RESOURCES;
  1106. goto JoinMulticastGroupEnd;
  1107. }
  1108. }
  1109. //
  1110. // Search the IGMP link for the multicast group. If a matching group is not
  1111. // found then release the lock, allocate a group and search again. If the
  1112. // group is still not found, add the newly allocated group.
  1113. //
  1114. Status = STATUS_SUCCESS;
  1115. while (TRUE) {
  1116. KeAcquireQueuedLock(IgmpLink->Lock);
  1117. LinkLockHeld = TRUE;
  1118. Group = NetpIgmpLookupGroup(IgmpLink, GroupAddress);
  1119. if (Group != NULL) {
  1120. Group->JoinCount += 1;
  1121. goto JoinMulticastGroupEnd;
  1122. }
  1123. if (NewGroup == NULL) {
  1124. KeReleaseQueuedLock(IgmpLink->Lock);
  1125. LinkLockHeld = FALSE;
  1126. NewGroup = NetpIgmpCreateGroup(IgmpLink, GroupAddress);
  1127. if (NewGroup == NULL) {
  1128. Status = STATUS_INSUFFICIENT_RESOURCES;
  1129. goto JoinMulticastGroupEnd;
  1130. }
  1131. continue;
  1132. }
  1133. //
  1134. // Add the newly allocated group to the link's list.
  1135. //
  1136. INSERT_BEFORE(&(NewGroup->ListEntry), &(IgmpLink->MulticastGroupList));
  1137. IgmpLink->GroupCount += 1;
  1138. break;
  1139. }
  1140. //
  1141. // Initialize the send count to the robustness variable. This will cause
  1142. // multiple join messages to be sent, up to the robustness count.
  1143. //
  1144. NewGroup->SendCount = IgmpLink->RobustnessVariable;
  1145. //
  1146. // An initial join sends state change messages and at least one message
  1147. // will be sent, so start the group as the last reporter.
  1148. //
  1149. NewGroup->Flags |= IGMP_MULTICAST_GROUP_FLAG_STATE_CHANGE |
  1150. IGMP_MULTICAST_GROUP_FLAG_LAST_REPORT;
  1151. //
  1152. // Take an extra reference on the new group so that it is not destroyed
  1153. // while sending the report. Once the lock is released, a leave request
  1154. // could run through and attempt to take it down.
  1155. //
  1156. NetpIgmpGroupAddReference(NewGroup);
  1157. KeReleaseQueuedLock(IgmpLink->Lock);
  1158. LinkLockHeld = FALSE;
  1159. //
  1160. // Actually send out the group's join IGMP state change messages.
  1161. //
  1162. NetpIgmpSendGroupReport(NewGroup);
  1163. JoinMulticastGroupEnd:
  1164. if (LinkLockHeld != FALSE) {
  1165. KeReleaseQueuedLock(IgmpLink->Lock);
  1166. }
  1167. if (IgmpLink != NULL) {
  1168. NetpIgmpLinkReleaseReference(IgmpLink);
  1169. }
  1170. if (NewGroup != NULL) {
  1171. NetpIgmpGroupReleaseReference(NewGroup);
  1172. }
  1173. if (Group != NULL) {
  1174. NetpIgmpGroupReleaseReference(Group);
  1175. }
  1176. return Status;
  1177. }
  1178. KSTATUS
  1179. NetpIgmpLeaveMulticastGroup (
  1180. PNET_NETWORK_MULTICAST_REQUEST Request
  1181. )
  1182. /*++
  1183. Routine Description:
  1184. This routine removes the local system from a multicast group. If this is
  1185. the last request to leave a multicast group on the link, then a IGMP leave
  1186. message is sent out over the network.
  1187. Arguments:
  1188. Request - Supplies a pointer to a multicast request, which includes the
  1189. address of the group to leave and the network link that has previously
  1190. joined the group.
  1191. Return Value:
  1192. Status code.
  1193. --*/
  1194. {
  1195. PIGMP_MULTICAST_GROUP Group;
  1196. PIGMP_LINK IgmpLink;
  1197. BOOL LinkLockHeld;
  1198. BOOL LinkUp;
  1199. PIP4_ADDRESS MulticastAddress;
  1200. KSTATUS Status;
  1201. Group = NULL;
  1202. IgmpLink = NULL;
  1203. LinkLockHeld = FALSE;
  1204. MulticastAddress = (PIP4_ADDRESS)Request->MulticastAddress;
  1205. //
  1206. // If the address is not reportable, an IGMP group was never made for it.
  1207. //
  1208. if (NetpIgmpIsReportableAddress(MulticastAddress->Address) == FALSE) {
  1209. return STATUS_SUCCESS;
  1210. }
  1211. //
  1212. // Now see if there is an IGMP link for the given network link.
  1213. //
  1214. IgmpLink = NetpIgmpLookupLink(Request->Link);
  1215. if (IgmpLink == NULL) {
  1216. Status = STATUS_INVALID_ADDRESS;
  1217. goto LeaveMulticastGroupEnd;
  1218. }
  1219. //
  1220. // Search the IGMP link for the multicast group. If a matching group is not
  1221. // found then the request fails.
  1222. //
  1223. KeAcquireQueuedLock(IgmpLink->Lock);
  1224. LinkLockHeld = TRUE;
  1225. Group = NetpIgmpLookupGroup(IgmpLink, MulticastAddress);
  1226. if (Group == NULL) {
  1227. Status = STATUS_INVALID_ADDRESS;
  1228. goto LeaveMulticastGroupEnd;
  1229. }
  1230. //
  1231. // If this is not the last leave request for the group, the call is
  1232. // successful, but takes no further action. The link remains joined to the
  1233. // multicast group.
  1234. //
  1235. Group->JoinCount -= 1;
  1236. if (Group->JoinCount != 0) {
  1237. goto LeaveMulticastGroupEnd;
  1238. }
  1239. //
  1240. // Otherwise it's time for the group to go.
  1241. //
  1242. LIST_REMOVE(&(Group->ListEntry));
  1243. Group->ListEntry.Next = NULL;
  1244. IgmpLink->GroupCount -= 1;
  1245. //
  1246. // The number of leave messages sent is dictated by the robustness variable.
  1247. //
  1248. Group->SendCount = IgmpLink->RobustnessVariable;
  1249. //
  1250. // Leave messages are state change messages.
  1251. //
  1252. Group->Flags |= IGMP_MULTICAST_GROUP_FLAG_STATE_CHANGE;
  1253. //
  1254. // Release the lock and flush out any reports that may be in the works.
  1255. //
  1256. KeReleaseQueuedLock(IgmpLink->Lock);
  1257. LinkLockHeld = FALSE;
  1258. KeCancelTimer(Group->Timer.Timer);
  1259. KeFlushDpc(Group->Timer.Dpc);
  1260. KeCancelWorkItem(Group->Timer.WorkItem);
  1261. KeFlushWorkItem(Group->Timer.WorkItem);
  1262. //
  1263. // The send count should not have been modified.
  1264. //
  1265. ASSERT(Group->SendCount == IgmpLink->RobustnessVariable);
  1266. //
  1267. // If the link is up, start sending leave messages, up to the robustness
  1268. // count. The group's initial reference will be released after the last
  1269. // leave message is sent.
  1270. //
  1271. NetGetLinkState(IgmpLink->Link, &LinkUp, NULL);
  1272. if (LinkUp != FALSE) {
  1273. NetpIgmpSendGroupLeave(Group);
  1274. //
  1275. // Otherwise don't bother with the leave messages and just destroy the
  1276. // group immediately.
  1277. //
  1278. } else {
  1279. NetpIgmpGroupReleaseReference(Group);
  1280. }
  1281. LeaveMulticastGroupEnd:
  1282. if (LinkLockHeld != FALSE) {
  1283. KeReleaseQueuedLock(IgmpLink->Lock);
  1284. }
  1285. if (IgmpLink != NULL) {
  1286. NetpIgmpLinkReleaseReference(IgmpLink);
  1287. }
  1288. if (Group != NULL) {
  1289. NetpIgmpGroupReleaseReference(Group);
  1290. }
  1291. return Status;
  1292. }
  1293. VOID
  1294. NetpIgmpProcessQuery (
  1295. PIGMP_LINK IgmpLink,
  1296. PNET_PACKET_BUFFER Packet,
  1297. PNETWORK_ADDRESS SourceAddress,
  1298. PNETWORK_ADDRESS DestinationAddress
  1299. )
  1300. /*++
  1301. Routine Description:
  1302. This routine processes an IGMP query message.
  1303. In host mode, this generates a report for each multicast group to which the
  1304. receiving link belongs.
  1305. In router mode, a query message indicates that there is another multicast
  1306. router on the local network. If this link has a higher IP address than the
  1307. sender, this link will not send queries until the "other querier present
  1308. interval" expires. Router mode is not currently supported.
  1309. Arguments:
  1310. IgmpLink - Supplies a pointer to the IGMP link that received the packet.
  1311. Packet - Supplies a pointer to a structure describing the incoming packet.
  1312. This structure may be used as a scratch space while this routine
  1313. executes and the packet travels up the stack, but will not be accessed
  1314. after this routine returns.
  1315. SourceAddress - Supplies a pointer to the source (remote) address that the
  1316. packet originated from. This memory will not be referenced once the
  1317. function returns, it can be stack allocated.
  1318. DestinationAddress - Supplies a pointer to the destination (local) address
  1319. that the packet is heading to. This memory will not be referenced once
  1320. the function returns, it can be stack allocated.
  1321. Return Value:
  1322. None.
  1323. --*/
  1324. {
  1325. PLIST_ENTRY CurrentEntry;
  1326. ULONGLONG CurrentTime;
  1327. PIP4_ADDRESS Destination;
  1328. PIGMP_MULTICAST_GROUP Group;
  1329. ULONG Length;
  1330. UCHAR MaxResponseCode;
  1331. ULONG MaxResponseTime;
  1332. PIGMP_MESSAGE Query;
  1333. ULONG QueryInterval;
  1334. PIGMP_QUERY_V3 QueryV3;
  1335. ULONG RobustnessVariable;
  1336. IGMP_VERSION Version;
  1337. Destination = (PIP4_ADDRESS)DestinationAddress;
  1338. //
  1339. // Determine which version of query message was received. An 8 octet long
  1340. // message with a max response code of 0 is an IGMPv1 query message. An 8
  1341. // octet long message with a non-zero max response code is an IGMPv2 query
  1342. // message. A message with a length greater than or equal to 12 octets is
  1343. // an IGMPv3 query message. Any other message must be ignored.
  1344. //
  1345. Query = (PIGMP_MESSAGE)(Packet->Buffer + Packet->DataOffset);
  1346. Length = Packet->FooterOffset - Packet->DataOffset;
  1347. MaxResponseCode = Query->Header.MaxResponseCode;
  1348. Version = IgmpVersion3;
  1349. if (Length == sizeof(IGMP_MESSAGE)) {
  1350. if (MaxResponseCode == 0) {
  1351. Version = IgmpVersion1;
  1352. MaxResponseCode = IGMP_QUERY_V1_MAX_RESPONSE_CODE;
  1353. } else {
  1354. Version = IgmpVersion2;
  1355. }
  1356. NetpIgmpQueueCompatibilityTimer(IgmpLink, Version);
  1357. } else if (Length >= sizeof(IGMP_QUERY_V3)) {
  1358. QueryV3 = (PIGMP_QUERY_V3)Query;
  1359. QueryInterval = IGMP_CONVERT_TIME_CODE_TO_TIME(
  1360. QueryV3->QueryIntervalCode);
  1361. RobustnessVariable = (QueryV3->Flags &
  1362. IGMP_QUERY_FLAG_ROBUSTNESS_MASK) >>
  1363. IGMP_QUERY_FLAG_ROBUSTNESS_SHIFT;
  1364. //
  1365. // Update the query interval and robustness variable if they are
  1366. // non-zero.
  1367. //
  1368. if (QueryInterval != 0) {
  1369. IgmpLink->QueryInterval = QueryInterval;
  1370. }
  1371. if (RobustnessVariable != 0) {
  1372. IgmpLink->RobustnessVariable = RobustnessVariable;
  1373. }
  1374. } else {
  1375. return;
  1376. }
  1377. //
  1378. // Version 2 and 3 queries without the router-alert option should be
  1379. // ignored for security reasons - theoretically helps to detect forged
  1380. // queries from outside the local network.
  1381. //
  1382. if ((Version == IgmpVersion3) || (Version == IgmpVersion2)) {
  1383. if ((Packet->Flags & NET_PACKET_FLAG_ROUTER_ALERT) == 0) {
  1384. return;
  1385. }
  1386. }
  1387. //
  1388. // All general queries not sent to the all-systems address (224.0.0.1)
  1389. // should be ignored for security reasons - the same forged query
  1390. // detection discussed above.
  1391. //
  1392. if ((Query->GroupAddress == 0) &&
  1393. (Destination->Address != IGMP_ALL_SYSTEMS_ADDRESS)) {
  1394. return;
  1395. }
  1396. //
  1397. // Ignore queries that target the all systems address. No reports are
  1398. // supposed to be sent for the all systems address, making a query quite
  1399. // mysterious.
  1400. //
  1401. if (Query->GroupAddress == IGMP_ALL_SYSTEMS_ADDRESS) {
  1402. return;
  1403. }
  1404. //
  1405. // Calculate the maximum response time. For query messages, the time unit
  1406. // is 1/10th of a second.
  1407. //
  1408. MaxResponseTime = IGMP_CONVERT_TIME_CODE_TO_TIME(MaxResponseCode);
  1409. //
  1410. // The reports are not sent immediately, but delayed based on the max
  1411. // response code.
  1412. //
  1413. KeAcquireQueuedLock(IgmpLink->Lock);
  1414. //
  1415. // Always save the max response time.
  1416. //
  1417. IgmpLink->MaxResponseTime = MaxResponseTime;
  1418. //
  1419. // If the host is operating in IGMPv3 mode and this is a general query, set
  1420. // the global report timer. IGMPv3 can send one report that includes
  1421. // information for all of the host's multicast memberships.
  1422. //
  1423. CurrentTime = KeGetRecentTimeCounter();
  1424. if ((IgmpLink->CompatibilityMode == IgmpVersion3) &&
  1425. (Query->GroupAddress == 0)) {
  1426. NetpIgmpQueueReportTimer(&(IgmpLink->ReportTimer),
  1427. CurrentTime,
  1428. MaxResponseTime);
  1429. //
  1430. // Otherwise, iterate over the list of multicast groups to which this
  1431. // link subscribes and update the timer for each group that matches the
  1432. // query's group address - or all groups if it is a generic query.
  1433. //
  1434. } else {
  1435. CurrentEntry = IgmpLink->MulticastGroupList.Next;
  1436. while (CurrentEntry != &(IgmpLink->MulticastGroupList)) {
  1437. Group = LIST_VALUE(CurrentEntry, IGMP_MULTICAST_GROUP, ListEntry);
  1438. if ((Query->GroupAddress == 0) ||
  1439. (Query->GroupAddress == Group->Address)) {
  1440. Group->Flags &= ~IGMP_MULTICAST_GROUP_FLAG_STATE_CHANGE;
  1441. if (Group->SendCount == 0) {
  1442. Group->SendCount = 1;
  1443. }
  1444. NetpIgmpQueueReportTimer(&(Group->Timer),
  1445. CurrentTime,
  1446. MaxResponseTime);
  1447. }
  1448. CurrentEntry = CurrentEntry->Next;
  1449. }
  1450. }
  1451. KeReleaseQueuedLock(IgmpLink->Lock);
  1452. return;
  1453. }
  1454. VOID
  1455. NetpIgmpProcessReport (
  1456. PIGMP_LINK IgmpLink,
  1457. PNET_PACKET_BUFFER Packet,
  1458. PNETWORK_ADDRESS SourceAddress,
  1459. PNETWORK_ADDRESS DestinationAddress
  1460. )
  1461. /*++
  1462. Routine Description:
  1463. This routine processes an IGMP report message.
  1464. In host mode, this cancels any pending report messages for the reported
  1465. multicast group. A router only needs to receive one report per multicast
  1466. group on the local physical network. It does not need to know which
  1467. specific hosts are subcribed to a group, just that at least one host is
  1468. subscribed to a group.
  1469. In router mode, a report should enabling forwarding packets destined for
  1470. the reported multicast group. Router mode is not currently supported.
  1471. Arguments:
  1472. IgmpLink - Supplies a pointer to the IGMP link that received the packet.
  1473. Packet - Supplies a pointer to a structure describing the incoming packet.
  1474. This structure may be used as a scratch space while this routine
  1475. executes and the packet travels up the stack, but will not be accessed
  1476. after this routine returns.
  1477. SourceAddress - Supplies a pointer to the source (remote) address that the
  1478. packet originated from. This memory will not be referenced once the
  1479. function returns, it can be stack allocated.
  1480. DestinationAddress - Supplies a pointer to the destination (local) address
  1481. that the packet is heading to. This memory will not be referenced once
  1482. the function returns, it can be stack allocated.
  1483. Return Value:
  1484. None.
  1485. --*/
  1486. {
  1487. PLIST_ENTRY CurrentEntry;
  1488. PIP4_ADDRESS Destination;
  1489. PIGMP_MULTICAST_GROUP Group;
  1490. ULONG Length;
  1491. PIP4_ADDRESS LocalAddress;
  1492. PIGMP_MESSAGE Report;
  1493. PIP4_ADDRESS Source;
  1494. PIP4_ADDRESS SubnetAddress;
  1495. //
  1496. // IGMPv3 reports are always ignored. The size of the report must be 8
  1497. // octets.
  1498. //
  1499. Report = (PIGMP_MESSAGE)(Packet->Buffer + Packet->DataOffset);
  1500. Length = Packet->FooterOffset - Packet->DataOffset;
  1501. if (Length != sizeof(IGMP_MESSAGE)) {
  1502. return;
  1503. }
  1504. //
  1505. // Reports from the any address must be accepted, otherwise the source must
  1506. // be from the local subnet.
  1507. //
  1508. Source = (PIP4_ADDRESS)SourceAddress;
  1509. if (Source->Address != 0) {
  1510. SubnetAddress = (PIP4_ADDRESS)&(IgmpLink->LinkAddress->Subnet);
  1511. LocalAddress = (PIP4_ADDRESS)&(IgmpLink->LinkAddress->Address);
  1512. if ((LocalAddress->Address & SubnetAddress->Address) !=
  1513. (Source->Address & SubnetAddress->Address)) {
  1514. RtlDebugPrint("IGMP: Ignoring report from: \n");
  1515. NetDebugPrintAddress((PNETWORK_ADDRESS)SourceAddress);
  1516. RtlDebugPrint("IGMP: It is not in the local network of: \n");
  1517. NetDebugPrintAddress((PNETWORK_ADDRESS)LocalAddress);
  1518. RtlDebugPrint("IGMP: Subnet mask is: \n");
  1519. NetDebugPrintAddress((PNETWORK_ADDRESS)SubnetAddress);
  1520. return;
  1521. }
  1522. }
  1523. //
  1524. // Version 2 reports without the router-alert option should be ignored for
  1525. // security reasons - theoretically helps to detect forged queries from
  1526. // outside the local network.
  1527. //
  1528. if (Report->Header.Type == IGMP_MESSAGE_TYPE_REPORT_V2) {
  1529. if ((Packet->Flags & NET_PACKET_FLAG_ROUTER_ALERT) == 0) {
  1530. return;
  1531. }
  1532. }
  1533. //
  1534. // The report should have been sent to the multicast group it was reporting
  1535. // on.
  1536. //
  1537. Destination = (PIP4_ADDRESS)DestinationAddress;
  1538. if ((Destination->Address != Report->GroupAddress) ||
  1539. (Destination->Address == 0)) {
  1540. return;
  1541. }
  1542. //
  1543. // If this IGMP link belongs to the multicast group, cancel any pending
  1544. // reports and record that this link was not the last to send a report.
  1545. //
  1546. KeAcquireQueuedLock(IgmpLink->Lock);
  1547. CurrentEntry = IgmpLink->MulticastGroupList.Next;
  1548. while (CurrentEntry != &(IgmpLink->MulticastGroupList)) {
  1549. Group = LIST_VALUE(CurrentEntry, IGMP_MULTICAST_GROUP, ListEntry);
  1550. if (Report->GroupAddress == Group->Address) {
  1551. KeCancelTimer(Group->Timer.Timer);
  1552. Group->Flags &= ~IGMP_MULTICAST_GROUP_FLAG_LAST_REPORT;
  1553. break;
  1554. }
  1555. CurrentEntry = CurrentEntry->Next;
  1556. }
  1557. KeReleaseQueuedLock(IgmpLink->Lock);
  1558. return;
  1559. }
  1560. VOID
  1561. NetpIgmpQueueReportTimer (
  1562. PIGMP_TIMER ReportTimer,
  1563. ULONGLONG StartTime,
  1564. ULONG MaxResponseTime
  1565. )
  1566. /*++
  1567. Routine Description:
  1568. This routine queues the given report timer to expire between 0 and the
  1569. maximum delay time from the given start time.
  1570. Arguments:
  1571. ReportTimer - Supplies a pointer to the report timer that needs to be
  1572. queued.
  1573. StartTime - Supplies the starting time to which the calculated delay will
  1574. be added. This should be in timer ticks.
  1575. MaxResponseTime - Supplies the maximum responce time supplied by the IGMP
  1576. query that prompted the report. It is in 1/10th of a second units.
  1577. Return Value:
  1578. None.
  1579. --*/
  1580. {
  1581. ULONGLONG CurrentDueTime;
  1582. ULONG Delay;
  1583. ULONGLONG DelayInMicroseconds;
  1584. ULONGLONG DueTime;
  1585. KSTATUS Status;
  1586. //
  1587. // The random delay is selected from the range (0, MaxResponseTime].
  1588. //
  1589. KeGetRandomBytes(&Delay, sizeof(Delay));
  1590. Delay = (Delay % MaxResponseTime) + 1;
  1591. DelayInMicroseconds = Delay * IGMP_MICROSECONDS_PER_QUERY_TIME_UNIT;
  1592. DueTime = StartTime + KeConvertMicrosecondsToTimeTicks(DelayInMicroseconds);
  1593. CurrentDueTime = KeGetTimerDueTime(ReportTimer->Timer);
  1594. //
  1595. // If the current due time is non-zero and less than the due time, do
  1596. // nothing. The report is already scheduled to be sent.
  1597. //
  1598. if ((CurrentDueTime != 0) && (CurrentDueTime <= DueTime)) {
  1599. return;
  1600. }
  1601. //
  1602. // Otherwise, cancel the timer and reschedule it for the earlier time. If
  1603. // the cancel is too late, then the timer just went off and the report
  1604. // will be sent. Do not reschedule the timer.
  1605. //
  1606. if (CurrentDueTime != 0) {
  1607. Status = KeCancelTimer(ReportTimer->Timer);
  1608. if (Status == STATUS_TOO_LATE) {
  1609. return;
  1610. }
  1611. }
  1612. KeQueueTimer(ReportTimer->Timer,
  1613. TimerQueueSoft,
  1614. DueTime,
  1615. 0,
  1616. 0,
  1617. ReportTimer->Dpc);
  1618. return;
  1619. }
  1620. VOID
  1621. NetpIgmpTimerDpcRoutine (
  1622. PDPC Dpc
  1623. )
  1624. /*++
  1625. Routine Description:
  1626. This routine implements the IGMP timer DPC that gets called after a timer
  1627. expires.
  1628. Arguments:
  1629. Dpc - Supplies a pointer to the DPC that is running.
  1630. Return Value:
  1631. None.
  1632. --*/
  1633. {
  1634. PIGMP_TIMER ReportTimer;
  1635. ReportTimer = (PIGMP_TIMER)Dpc->UserData;
  1636. KeQueueWorkItem(ReportTimer->WorkItem);
  1637. return;
  1638. }
  1639. VOID
  1640. NetpIgmpGroupTimeoutWorker (
  1641. PVOID Parameter
  1642. )
  1643. /*++
  1644. Routine Description:
  1645. This routine performs the low level work when an IGMP group report timer
  1646. expires. It sends a report or leave message for the group.
  1647. Arguments:
  1648. Parameter - Supplies a pointer to the IGMP group whose timer expired.
  1649. Return Value:
  1650. None.
  1651. --*/
  1652. {
  1653. PIGMP_MULTICAST_GROUP Group;
  1654. //
  1655. // The worker thread should only send leave messages after the first leave
  1656. // message is sent by the initial leave request. The group will be
  1657. // destroyed after the last leave message, so don't touch the group
  1658. // structure after the call to send a leave message.
  1659. //
  1660. Group = (PIGMP_MULTICAST_GROUP)Parameter;
  1661. if ((Group->Flags & IGMP_MULTICAST_GROUP_FLAG_LEAVE_SENT) != 0) {
  1662. NetpIgmpSendGroupLeave(Group);
  1663. //
  1664. // Otherwise the timer has expired to send a simple group report.
  1665. //
  1666. } else {
  1667. NetpIgmpSendGroupReport(Group);
  1668. }
  1669. return;
  1670. }
  1671. VOID
  1672. NetpIgmpLinkReportTimeoutWorker (
  1673. PVOID Parameter
  1674. )
  1675. /*++
  1676. Routine Description:
  1677. This routine performs the low level work when an IGMP link report timer
  1678. expires. It sends a IGMPv3 report message for all groups.
  1679. Arguments:
  1680. Parameter - Supplies a pointer to the IGMP link whose link report timer
  1681. expired.
  1682. Return Value:
  1683. None.
  1684. --*/
  1685. {
  1686. PIGMP_LINK IgmpLink;
  1687. IgmpLink = (PIGMP_LINK)Parameter;
  1688. NetpIgmpSendLinkReport(IgmpLink);
  1689. return;
  1690. }
  1691. VOID
  1692. NetpIgmpLinkCompatibilityTimeoutWorker (
  1693. PVOID Parameter
  1694. )
  1695. /*++
  1696. Routine Description:
  1697. This routine performs the low level work when a compatibility mode timer
  1698. expires. It determines the new compatability mode.
  1699. Arguments:
  1700. Parameter - Supplies a pointer to the IGMP link whose compatibility timer
  1701. expired.
  1702. Return Value:
  1703. None.
  1704. --*/
  1705. {
  1706. PIGMP_LINK IgmpLink;
  1707. IgmpLink = (PIGMP_LINK)Parameter;
  1708. KeAcquireQueuedLock(IgmpLink->Lock);
  1709. NetpIgmpUpdateCompatibilityMode(IgmpLink);
  1710. KeReleaseQueuedLock(IgmpLink->Lock);
  1711. return;
  1712. }
  1713. VOID
  1714. NetpIgmpQueueCompatibilityTimer (
  1715. PIGMP_LINK IgmpLink,
  1716. IGMP_VERSION CompatibilityMode
  1717. )
  1718. /*++
  1719. Routine Description:
  1720. This routine queues an IGMP compatibility timer for the given mode.
  1721. Arguments:
  1722. IgmpLink - Supplies a pointer to IGMP link whose compatibility timer needs
  1723. to be set.
  1724. CompatibilityMode - Supplies a pointer to the compatibility mode whose
  1725. timer needs to be set.
  1726. Return Value:
  1727. None.
  1728. --*/
  1729. {
  1730. ULONGLONG CurrentDueTime;
  1731. ULONG DelayInMicroseconds;
  1732. ULONGLONG DueTime;
  1733. ULONGLONG StartTime;
  1734. PIGMP_TIMER Timer;
  1735. //
  1736. // The compatibility mode interval is calculated as follows:
  1737. //
  1738. // (Robustness Variable * Query Interval) + (Query Response Interval)
  1739. //
  1740. // The Query Response Interval is the same as the maximum response time
  1741. // provided by the last query.
  1742. //
  1743. DelayInMicroseconds = IgmpLink->RobustnessVariable *
  1744. IgmpLink->QueryInterval *
  1745. MICROSECONDS_PER_SECOND;
  1746. DelayInMicroseconds += IgmpLink->MaxResponseTime *
  1747. IGMP_MICROSECONDS_PER_QUERY_TIME_UNIT;
  1748. Timer = &(IgmpLink->CompatibilityTimer[CompatibilityMode]);
  1749. StartTime = KeGetRecentTimeCounter();
  1750. DueTime = StartTime + KeConvertMicrosecondsToTimeTicks(DelayInMicroseconds);
  1751. //
  1752. // If the timer is already scheduled, then it needs to be extended for
  1753. // another compatibility timeout interval. Cancel it and requeue it. It's
  1754. // OK if the DPC fires the work item in the meantime. The correct mode will
  1755. // be set once the lock can be acquired by the work item.
  1756. //
  1757. KeAcquireQueuedLock(IgmpLink->Lock);
  1758. CurrentDueTime = KeGetTimerDueTime(Timer->Timer);
  1759. if (CurrentDueTime != 0) {
  1760. KeCancelTimer(Timer->Timer);
  1761. }
  1762. KeQueueTimer(Timer->Timer,
  1763. TimerQueueSoft,
  1764. DueTime,
  1765. 0,
  1766. 0,
  1767. Timer->Dpc);
  1768. NetpIgmpUpdateCompatibilityMode(IgmpLink);
  1769. KeReleaseQueuedLock(IgmpLink->Lock);
  1770. return;
  1771. }
  1772. VOID
  1773. NetpIgmpUpdateCompatibilityMode (
  1774. PIGMP_LINK IgmpLink
  1775. )
  1776. /*++
  1777. Routine Description:
  1778. This routine updates the given IGMP link's compatibility mode based on the
  1779. state of the compatibility timers. It assumes the IGMP link's lock is held.
  1780. Arguments:
  1781. IgmpLink - Supplies a pointer to an IGMP link.
  1782. Return Value:
  1783. None.
  1784. --*/
  1785. {
  1786. PLIST_ENTRY CurrentEntry;
  1787. ULONGLONG DueTime;
  1788. PIGMP_MULTICAST_GROUP Group;
  1789. IGMP_VERSION ModeIndex;
  1790. IGMP_VERSION NewMode;
  1791. PIGMP_TIMER Timer;
  1792. ASSERT(KeIsQueuedLockHeld(IgmpLink->Lock) != FALSE);
  1793. NewMode = IgmpVersion3;
  1794. for (ModeIndex = IgmpVersion1;
  1795. ModeIndex < IGMP_COMPATIBILITY_MODE_COUNT;
  1796. ModeIndex += 1) {
  1797. Timer = &(IgmpLink->CompatibilityTimer[ModeIndex]);
  1798. DueTime = KeGetTimerDueTime(Timer->Timer);
  1799. if (DueTime != 0) {
  1800. NewMode = ModeIndex;
  1801. break;
  1802. }
  1803. }
  1804. //
  1805. // If compatibility mode is about to change, cancel all pending timers.
  1806. //
  1807. if (NewMode != IgmpLink->CompatibilityMode) {
  1808. KeCancelTimer(IgmpLink->ReportTimer.Timer);
  1809. CurrentEntry = IgmpLink->MulticastGroupList.Next;
  1810. while (CurrentEntry != &(IgmpLink->MulticastGroupList)) {
  1811. Group = LIST_VALUE(CurrentEntry, IGMP_MULTICAST_GROUP, ListEntry);
  1812. KeCancelTimer(Group->Timer.Timer);
  1813. CurrentEntry = CurrentEntry->Next;
  1814. }
  1815. }
  1816. IgmpLink->CompatibilityMode = NewMode;
  1817. return;
  1818. }
  1819. VOID
  1820. NetpIgmpSendGroupReport (
  1821. PIGMP_MULTICAST_GROUP Group
  1822. )
  1823. /*++
  1824. Routine Description:
  1825. This routine sends a IGMP report message for a specific multicast group.
  1826. Arguments:
  1827. Group - Supplies a pointer to the multicast group to report.
  1828. Return Value:
  1829. None.
  1830. --*/
  1831. {
  1832. ULONG BufferFlags;
  1833. ULONG BufferSize;
  1834. IGMP_VERSION CompatibilityMode;
  1835. IP4_ADDRESS DestinationAddress;
  1836. PIGMP_GROUP_RECORD_V3 GroupRecord;
  1837. PIGMP_HEADER Header;
  1838. NET_PACKET_LIST NetPacketList;
  1839. PNET_PACKET_BUFFER Packet;
  1840. PIGMP_MESSAGE Report;
  1841. PIGMP_REPORT_V3 ReportV3;
  1842. KSTATUS Status;
  1843. UCHAR Type;
  1844. //
  1845. // Reports should be heading to reportable groups only.
  1846. //
  1847. ASSERT(NetpIgmpIsReportableAddress(Group->Address) != FALSE);
  1848. //
  1849. // Snap the compatibility mode.
  1850. //
  1851. CompatibilityMode = Group->IgmpLink->CompatibilityMode;
  1852. if (CompatibilityMode == IgmpVersion3) {
  1853. BufferSize = sizeof(IGMP_REPORT_V3) + sizeof(IGMP_GROUP_RECORD_V3);
  1854. ASSERT(BufferSize <= Group->IgmpLink->MaxPacketSize);
  1855. } else {
  1856. BufferSize = sizeof(IGMP_MESSAGE);
  1857. }
  1858. BufferFlags = NET_ALLOCATE_BUFFER_FLAG_ADD_DEVICE_LINK_HEADERS |
  1859. NET_ALLOCATE_BUFFER_FLAG_ADD_DEVICE_LINK_FOOTERS |
  1860. NET_ALLOCATE_BUFFER_FLAG_ADD_DATA_LINK_HEADERS |
  1861. NET_ALLOCATE_BUFFER_FLAG_ADD_DATA_LINK_FOOTERS;
  1862. Status = NetAllocateBuffer(IGMP_IP4_HEADER_SIZE,
  1863. BufferSize,
  1864. 0,
  1865. Group->IgmpLink->Link,
  1866. BufferFlags,
  1867. &Packet);
  1868. if (!KSUCCESS(Status)) {
  1869. return;
  1870. }
  1871. Type = IGMP_MESSAGE_TYPE_REPORT_V1;
  1872. DestinationAddress.Domain = NetDomainIp4;
  1873. Header = (PIGMP_HEADER)(Packet->Buffer + Packet->DataOffset);
  1874. switch (CompatibilityMode) {
  1875. case IgmpVersion3:
  1876. Type = IGMP_MESSAGE_TYPE_REPORT_V3;
  1877. DestinationAddress.Address = IGMP_ALL_ROUTERS_ADDRESS_V3;
  1878. ReportV3 = (PIGMP_REPORT_V3)Header;
  1879. ReportV3->Reserved = 0;
  1880. ReportV3->GroupRecordCount = CPU_TO_NETWORK16(1);
  1881. GroupRecord = (PIGMP_GROUP_RECORD_V3)(ReportV3 + 1);
  1882. if ((Group->Flags & IGMP_MULTICAST_GROUP_FLAG_STATE_CHANGE) != 0) {
  1883. GroupRecord->Type = IGMP_GROUP_RECORD_TYPE_CHANGE_TO_EXCLUDE_MODE;
  1884. } else {
  1885. GroupRecord->Type = IGMP_GROUP_RECORD_TYPE_MODE_IS_EXCLUDE;
  1886. }
  1887. GroupRecord->DataLength = 0;
  1888. GroupRecord->SourceAddressCount = CPU_TO_NETWORK16(0);
  1889. GroupRecord->MulticastAddress = Group->Address;
  1890. break;
  1891. case IgmpVersion2:
  1892. Type = IGMP_MESSAGE_TYPE_REPORT_V2;
  1893. //
  1894. // Fall through to version 1 in order to fill out the group address.
  1895. //
  1896. case IgmpVersion1:
  1897. Report = (PIGMP_MESSAGE)Header;
  1898. Report->GroupAddress = Group->Address;
  1899. DestinationAddress.Address = Group->Address;
  1900. break;
  1901. default:
  1902. ASSERT(FALSE);
  1903. NetFreeBuffer(Packet);
  1904. return;
  1905. }
  1906. //
  1907. // Fill out the IGMP header common to all versions and send it on to the
  1908. // common send routine.
  1909. //
  1910. Header->Type = Type;
  1911. Header->MaxResponseCode = 0;
  1912. Header->Checksum = 0;
  1913. Header->Checksum = NetChecksumData((PVOID)Header, BufferSize);
  1914. NET_INITIALIZE_PACKET_LIST(&NetPacketList);
  1915. NET_ADD_PACKET_TO_LIST(Packet, &NetPacketList);
  1916. NetpIgmpSendPackets(Group->IgmpLink,
  1917. (PNETWORK_ADDRESS)&DestinationAddress,
  1918. &NetPacketList);
  1919. //
  1920. // Note that this link sent the last report for this group, making it on
  1921. // the hook for sending the leave messages. Also test to see whether more
  1922. // join messages need to be sent.
  1923. //
  1924. KeAcquireQueuedLock(Group->IgmpLink->Lock);
  1925. Group->Flags |= IGMP_MULTICAST_GROUP_FLAG_LAST_REPORT;
  1926. if (Group->ListEntry.Next != NULL) {
  1927. Group->SendCount -= 1;
  1928. if (Group->SendCount > 0) {
  1929. NetpIgmpQueueReportTimer(&(Group->Timer),
  1930. KeGetRecentTimeCounter(),
  1931. IGMP_DEFAULT_UNSOLICITED_REPORT_INTERVAL);
  1932. }
  1933. }
  1934. KeReleaseQueuedLock(Group->IgmpLink->Lock);
  1935. return;
  1936. }
  1937. VOID
  1938. NetpIgmpSendGroupLeave (
  1939. PIGMP_MULTICAST_GROUP Group
  1940. )
  1941. /*++
  1942. Routine Description:
  1943. This routine sends an IGMP leave message to the all routers multicast group.
  1944. Arguments:
  1945. Group - Supplies a pointer to the multicast group that the host is leaving.
  1946. Return Value:
  1947. None.
  1948. --*/
  1949. {
  1950. ULONG BufferFlags;
  1951. ULONG BufferSize;
  1952. IGMP_VERSION CompatibilityMode;
  1953. IP4_ADDRESS DestinationAddress;
  1954. BOOL DestroyGroup;
  1955. PIGMP_GROUP_RECORD_V3 GroupRecord;
  1956. PIGMP_HEADER Header;
  1957. PIGMP_MESSAGE Leave;
  1958. NET_PACKET_LIST NetPacketList;
  1959. PNET_PACKET_BUFFER Packet;
  1960. PIGMP_REPORT_V3 ReportV3;
  1961. KSTATUS Status;
  1962. UCHAR Type;
  1963. DestroyGroup = TRUE;
  1964. //
  1965. // Leave reports should be heading to reportable groups only.
  1966. //
  1967. ASSERT(NetpIgmpIsReportableAddress(Group->Address) != FALSE);
  1968. //
  1969. // If this link was not the last to report the group, then don't send
  1970. // a leave message.
  1971. //
  1972. if ((Group->Flags & IGMP_MULTICAST_GROUP_FLAG_LAST_REPORT) == 0) {
  1973. goto SendGroupLeaveEnd;
  1974. }
  1975. //
  1976. // Snap the current compatibility mode. No leave message needs to be sent
  1977. // if the host is operating in IGMPv1 mode.
  1978. //
  1979. CompatibilityMode = Group->IgmpLink->CompatibilityMode;
  1980. if (CompatibilityMode == IgmpVersion1) {
  1981. goto SendGroupLeaveEnd;
  1982. }
  1983. if (CompatibilityMode == IgmpVersion2) {
  1984. BufferSize = sizeof(IGMP_MESSAGE);
  1985. } else {
  1986. BufferSize = sizeof(IGMP_REPORT_V3) + sizeof(IGMP_GROUP_RECORD_V3);
  1987. ASSERT(CompatibilityMode == IgmpVersion3);
  1988. ASSERT(BufferSize <= Group->IgmpLink->MaxPacketSize);
  1989. }
  1990. BufferFlags = NET_ALLOCATE_BUFFER_FLAG_ADD_DEVICE_LINK_HEADERS |
  1991. NET_ALLOCATE_BUFFER_FLAG_ADD_DEVICE_LINK_FOOTERS |
  1992. NET_ALLOCATE_BUFFER_FLAG_ADD_DATA_LINK_HEADERS |
  1993. NET_ALLOCATE_BUFFER_FLAG_ADD_DATA_LINK_FOOTERS;
  1994. Status = NetAllocateBuffer(IGMP_IP4_HEADER_SIZE,
  1995. BufferSize,
  1996. 0,
  1997. Group->IgmpLink->Link,
  1998. BufferFlags,
  1999. &Packet);
  2000. if (!KSUCCESS(Status)) {
  2001. goto SendGroupLeaveEnd;
  2002. }
  2003. DestinationAddress.Domain = NetDomainIp4;
  2004. Header = (PIGMP_HEADER)(Packet->Buffer + Packet->DataOffset);
  2005. switch (CompatibilityMode) {
  2006. case IgmpVersion3:
  2007. Type = IGMP_MESSAGE_TYPE_REPORT_V3;
  2008. DestinationAddress.Address = IGMP_ALL_ROUTERS_ADDRESS_V3;
  2009. ReportV3 = (PIGMP_REPORT_V3)Header;
  2010. ReportV3->GroupRecordCount = CPU_TO_NETWORK16(1);
  2011. ReportV3->Reserved = 0;
  2012. GroupRecord = (PIGMP_GROUP_RECORD_V3)(ReportV3 + 1);
  2013. GroupRecord->Type = IGMP_GROUP_RECORD_TYPE_CHANGE_TO_INCLUDE_MODE;
  2014. GroupRecord->DataLength = 0;
  2015. GroupRecord->SourceAddressCount = CPU_TO_NETWORK16(0);
  2016. GroupRecord->MulticastAddress = Group->Address;
  2017. break;
  2018. case IgmpVersion2:
  2019. Type = IGMP_MESSAGE_TYPE_LEAVE_V2;
  2020. Leave = (PIGMP_MESSAGE)Header;
  2021. Leave->GroupAddress = Group->Address;
  2022. DestinationAddress.Address = IGMP_ALL_ROUTERS_ADDRESS;
  2023. break;
  2024. case IgmpVersion1:
  2025. default:
  2026. ASSERT(FALSE);
  2027. NetFreeBuffer(Packet);
  2028. goto SendGroupLeaveEnd;
  2029. }
  2030. Header->Type = Type;
  2031. Header->MaxResponseCode = 0;
  2032. Header->Checksum = 0;
  2033. Header->Checksum = NetChecksumData((PVOID)Header, BufferSize);
  2034. NET_INITIALIZE_PACKET_LIST(&NetPacketList);
  2035. NET_ADD_PACKET_TO_LIST(Packet, &NetPacketList);
  2036. NetpIgmpSendPackets(Group->IgmpLink,
  2037. (PNETWORK_ADDRESS)&DestinationAddress,
  2038. &NetPacketList);
  2039. //
  2040. // Note that a leave message has now been sent, allowing the worker to send
  2041. // more leave messages. If the worker were to send leave messages before
  2042. // an initial leave message is sent by the leave request, it may be doing
  2043. // so on behalf of a previous join message. This messes up the send count
  2044. // and reference counting.
  2045. //
  2046. KeAcquireQueuedLock(Group->IgmpLink->Lock);
  2047. Group->Flags |= IGMP_MULTICAST_GROUP_FLAG_LEAVE_SENT;
  2048. ASSERT(Group->SendCount > 0);
  2049. Group->SendCount -= 1;
  2050. if (Group->SendCount > 0) {
  2051. NetpIgmpQueueReportTimer(&(Group->Timer),
  2052. KeGetRecentTimeCounter(),
  2053. IGMP_DEFAULT_UNSOLICITED_REPORT_INTERVAL);
  2054. DestroyGroup = FALSE;
  2055. }
  2056. KeReleaseQueuedLock(Group->IgmpLink->Lock);
  2057. SendGroupLeaveEnd:
  2058. if (DestroyGroup != FALSE) {
  2059. NetpIgmpGroupReleaseReference(Group);
  2060. }
  2061. return;
  2062. }
  2063. VOID
  2064. NetpIgmpSendLinkReport (
  2065. PIGMP_LINK IgmpLink
  2066. )
  2067. /*++
  2068. Routine Description:
  2069. This routine sends a IGMP report message for the whole link.
  2070. Arguments:
  2071. IgmpLink - Supplies a pointer to the IGMP link to report.
  2072. Return Value:
  2073. None.
  2074. --*/
  2075. {
  2076. ULONG BufferFlags;
  2077. ULONG BufferSize;
  2078. PLIST_ENTRY CurrentEntry;
  2079. ULONG CurrentGroupCount;
  2080. IP4_ADDRESS DestinationAddress;
  2081. PIGMP_MULTICAST_GROUP Group;
  2082. PIGMP_GROUP_RECORD_V3 GroupRecord;
  2083. ULONG GroupSize;
  2084. PIGMP_HEADER Header;
  2085. NET_PACKET_LIST NetPacketList;
  2086. PNET_PACKET_BUFFER Packet;
  2087. ULONG RemainingGroupCount;
  2088. PIGMP_REPORT_V3 ReportV3;
  2089. USHORT SourceAddressCount;
  2090. KSTATUS Status;
  2091. //
  2092. // Send as many IGMPv3 "Current-State" records as required to notify the
  2093. // all routers group of all the multicast groups to which the given link
  2094. // belongs. This may take more than one packet if the link is subscribed to
  2095. // more than MAX_USHORT groups or if the number of groups requires a packet
  2096. // larger than the link's max transfer size.
  2097. //
  2098. NET_INITIALIZE_PACKET_LIST(&NetPacketList);
  2099. KeAcquireQueuedLock(IgmpLink->Lock);
  2100. RemainingGroupCount = IgmpLink->GroupCount;
  2101. CurrentEntry = IgmpLink->MulticastGroupList.Next;
  2102. while (RemainingGroupCount != 0) {
  2103. CurrentGroupCount = RemainingGroupCount;
  2104. if (CurrentGroupCount > IGMP_MAX_GROUP_RECORD_COUNT) {
  2105. CurrentGroupCount = IGMP_MAX_GROUP_RECORD_COUNT;
  2106. }
  2107. BufferSize = sizeof(IGMP_REPORT_V3) +
  2108. (sizeof(IGMP_GROUP_RECORD_V3) * CurrentGroupCount);
  2109. if (BufferSize > IgmpLink->MaxPacketSize) {
  2110. BufferSize = IgmpLink->MaxPacketSize;
  2111. CurrentGroupCount = (BufferSize - sizeof(IGMP_REPORT_V3)) /
  2112. sizeof(IGMP_GROUP_RECORD_V3);
  2113. }
  2114. RemainingGroupCount -= CurrentGroupCount;
  2115. BufferFlags = NET_ALLOCATE_BUFFER_FLAG_ADD_DEVICE_LINK_HEADERS |
  2116. NET_ALLOCATE_BUFFER_FLAG_ADD_DEVICE_LINK_FOOTERS |
  2117. NET_ALLOCATE_BUFFER_FLAG_ADD_DATA_LINK_HEADERS |
  2118. NET_ALLOCATE_BUFFER_FLAG_ADD_DATA_LINK_FOOTERS;
  2119. Status = NetAllocateBuffer(IGMP_IP4_HEADER_SIZE,
  2120. BufferSize,
  2121. 0,
  2122. IgmpLink->Link,
  2123. BufferFlags,
  2124. &Packet);
  2125. if (!KSUCCESS(Status)) {
  2126. break;
  2127. }
  2128. Header = (PIGMP_HEADER)(Packet->Buffer + Packet->DataOffset);
  2129. Header->Type = IGMP_MESSAGE_TYPE_REPORT_V3;
  2130. Header->MaxResponseCode = 0;
  2131. Header->Checksum = 0;
  2132. ReportV3 = (PIGMP_REPORT_V3)Header;
  2133. ReportV3->Reserved = 0;
  2134. ReportV3->GroupRecordCount = CPU_TO_NETWORK16(CurrentGroupCount);
  2135. GroupRecord = (PIGMP_GROUP_RECORD_V3)(ReportV3 + 1);
  2136. while (CurrentGroupCount != 0) {
  2137. ASSERT(CurrentEntry != &(IgmpLink->MulticastGroupList));
  2138. Group = LIST_VALUE(CurrentEntry, IGMP_MULTICAST_GROUP, ListEntry);
  2139. CurrentEntry = CurrentEntry->Next;
  2140. ASSERT(NetpIgmpIsReportableAddress(Group->Address) != FALSE);
  2141. CurrentGroupCount -= 1;
  2142. //
  2143. // The count should be accurate and eliminate the need to check for
  2144. // the head.
  2145. //
  2146. GroupRecord->Type = IGMP_GROUP_RECORD_TYPE_MODE_IS_EXCLUDE;
  2147. GroupRecord->DataLength = 0;
  2148. SourceAddressCount = 0;
  2149. GroupRecord->SourceAddressCount =
  2150. CPU_TO_NETWORK16(SourceAddressCount);
  2151. GroupRecord->MulticastAddress = Group->Address;
  2152. GroupSize = sizeof(IGMP_GROUP_RECORD_V3) +
  2153. (SourceAddressCount * sizeof(ULONG)) +
  2154. GroupRecord->DataLength;
  2155. GroupRecord =
  2156. (PIGMP_GROUP_RECORD_V3)((PUCHAR)GroupRecord + GroupSize);
  2157. }
  2158. Header->Checksum = NetChecksumData((PVOID)Header, BufferSize);
  2159. NET_ADD_PACKET_TO_LIST(Packet, &NetPacketList);
  2160. }
  2161. KeReleaseQueuedLock(IgmpLink->Lock);
  2162. if (NET_PACKET_LIST_EMPTY(&NetPacketList) != FALSE) {
  2163. return;
  2164. }
  2165. DestinationAddress.Domain = NetDomainIp4;
  2166. DestinationAddress.Address = IGMP_ALL_ROUTERS_ADDRESS_V3;
  2167. NetpIgmpSendPackets(IgmpLink,
  2168. (PNETWORK_ADDRESS)&DestinationAddress,
  2169. &NetPacketList);
  2170. return;
  2171. }
  2172. VOID
  2173. NetpIgmpSendPackets (
  2174. PIGMP_LINK IgmpLink,
  2175. PNETWORK_ADDRESS Destination,
  2176. PNET_PACKET_LIST PacketList
  2177. )
  2178. /*++
  2179. Routine Description:
  2180. This routine sends a list of IGMP packets out over the provided link to the
  2181. specified destination. It simply adds the IPv4 headers and sends the
  2182. packets down the stack.
  2183. Arguments:
  2184. IgmpLink - Supplies a pointer to the IGMP link over which to send the
  2185. packet.
  2186. Destination - Supplies a pointer to the destination address. This should be
  2187. a multicast address.
  2188. PacketList - Supplies a pointer to the list of packets to send.
  2189. Return Value:
  2190. None.
  2191. --*/
  2192. {
  2193. USHORT Checksum;
  2194. PLIST_ENTRY CurrentEntry;
  2195. PIP4_ADDRESS DestinationAddress;
  2196. NETWORK_ADDRESS DestinationPhysical;
  2197. PIP4_HEADER Header;
  2198. PNET_LINK Link;
  2199. PNET_LINK_ADDRESS_ENTRY LinkAddress;
  2200. PNET_PACKET_BUFFER Packet;
  2201. PULONG RouterAlert;
  2202. PNET_DATA_LINK_SEND Send;
  2203. PIP4_ADDRESS SourceAddress;
  2204. KSTATUS Status;
  2205. ULONG TotalLength;
  2206. Link = IgmpLink->Link;
  2207. LinkAddress = IgmpLink->LinkAddress;
  2208. DestinationAddress = (PIP4_ADDRESS)Destination;
  2209. SourceAddress = (PIP4_ADDRESS)&(LinkAddress->Address);
  2210. //
  2211. // Add the IPv4 header to each of the IGMP packets. Each packet includes
  2212. // the router alert option.
  2213. //
  2214. CurrentEntry = PacketList->Head.Next;
  2215. while (CurrentEntry != &(PacketList->Head)) {
  2216. Packet = LIST_VALUE(CurrentEntry, NET_PACKET_BUFFER, ListEntry);
  2217. CurrentEntry = CurrentEntry->Next;
  2218. ASSERT(Packet->DataOffset >= IGMP_IP4_HEADER_SIZE);
  2219. Packet->DataOffset -= IGMP_IP4_HEADER_SIZE;
  2220. //
  2221. // Fill out the IPv4 header. In order to avoid creating a socket and
  2222. // because IGMP only works on top of IPv4, the IGMP module sends IPv4
  2223. // packets directly to the physical layer.
  2224. //
  2225. Header = (PIP4_HEADER)(Packet->Buffer + Packet->DataOffset);
  2226. Header->VersionAndHeaderLength =
  2227. IP4_VERSION |
  2228. (UCHAR)(IGMP_IP4_HEADER_SIZE / sizeof(ULONG));
  2229. Header->Type = IP4_PRECEDENCE_NETWORK_CONTROL;
  2230. TotalLength = Packet->FooterOffset - Packet->DataOffset;
  2231. Header->TotalLength = CPU_TO_NETWORK16(TotalLength);
  2232. Header->Identification = 0;
  2233. Header->FragmentOffset = 0;
  2234. Header->TimeToLive = 1;
  2235. Header->Protocol = SOCKET_INTERNET_PROTOCOL_IGMP;
  2236. Header->HeaderChecksum = 0;
  2237. //
  2238. // The source address is supposed to be the link's IP address. If the
  2239. // link does not have an IP address assign, "0.0.0.0" is used. Either
  2240. // way, the correct value is in the link address entry's address field.
  2241. //
  2242. Header->SourceAddress = SourceAddress->Address;
  2243. Header->DestinationAddress = DestinationAddress->Address;
  2244. RouterAlert = (PULONG)(Header + 1);
  2245. *RouterAlert = IGMP_IP4_ROUTER_ALERT_OPTION;
  2246. if ((Link->Properties.Capabilities &
  2247. NET_LINK_CAPABILITY_TRANSMIT_IP_CHECKSUM_OFFLOAD) == 0) {
  2248. Checksum = NetChecksumData((PVOID)Header, IGMP_IP4_HEADER_SIZE);
  2249. Header->HeaderChecksum = Checksum;
  2250. } else {
  2251. Packet->Flags |= NET_PACKET_FLAG_IP_CHECKSUM_OFFLOAD;
  2252. }
  2253. }
  2254. //
  2255. // Get the physical address for the IPv4 multicast destination address.
  2256. //
  2257. Status = Link->DataLinkEntry->Interface.ConvertToPhysicalAddress(
  2258. Destination,
  2259. &DestinationPhysical,
  2260. NetAddressMulticast);
  2261. if (!KSUCCESS(Status)) {
  2262. goto IgmpSendPacketsEnd;
  2263. }
  2264. Send = Link->DataLinkEntry->Interface.Send;
  2265. Status = Send(Link->DataLinkContext,
  2266. PacketList,
  2267. &(LinkAddress->PhysicalAddress),
  2268. &DestinationPhysical,
  2269. IP4_PROTOCOL_NUMBER);
  2270. if (!KSUCCESS(Status)) {
  2271. goto IgmpSendPacketsEnd;
  2272. }
  2273. IgmpSendPacketsEnd:
  2274. if (!KSUCCESS(Status)) {
  2275. NetDestroyBufferList(PacketList);
  2276. }
  2277. return;
  2278. }
  2279. PIGMP_LINK
  2280. NetpIgmpCreateOrLookupLink (
  2281. PNET_LINK Link,
  2282. PNET_LINK_ADDRESS_ENTRY LinkAddress
  2283. )
  2284. /*++
  2285. Routine Description:
  2286. This routine creates an IGMP link associated with the given local address
  2287. and attempts to insert it into the tree. If an existing match is found,
  2288. then the existing link is returned.
  2289. Arguments:
  2290. Link - Supplies a pointer to the network link for which the IGMP link is
  2291. to be created.
  2292. LinkAddress - Supplies a pointer to the link address entry on the given
  2293. network link with which the IGMP link shall be associated.
  2294. Return Value:
  2295. Returns a pointer to the newly allocated IGMP link on success or NULL on
  2296. failure.
  2297. --*/
  2298. {
  2299. PNET_DATA_LINK_ENTRY DataLinkEntry;
  2300. NET_PACKET_SIZE_INFORMATION DataSizeInformation;
  2301. PRED_BLACK_TREE_NODE FoundNode;
  2302. PIGMP_LINK IgmpLink;
  2303. ULONG Index;
  2304. PNET_PACKET_SIZE_INFORMATION LinkSizeInformation;
  2305. ULONG MaxPacketSize;
  2306. PIGMP_LINK NewIgmpLink;
  2307. IGMP_LINK SearchLink;
  2308. KSTATUS Status;
  2309. IgmpLink = NULL;
  2310. NewIgmpLink = MmAllocatePagedPool(sizeof(IGMP_LINK), IGMP_ALLOCATION_TAG);
  2311. if (NewIgmpLink == NULL) {
  2312. Status = STATUS_INSUFFICIENT_RESOURCES;
  2313. goto CreateOrLookupLinkEnd;
  2314. }
  2315. RtlZeroMemory(NewIgmpLink, sizeof(IGMP_LINK));
  2316. NewIgmpLink->ReferenceCount = 1;
  2317. NetLinkAddReference(Link);
  2318. NewIgmpLink->Link = Link;
  2319. NewIgmpLink->LinkAddress = LinkAddress;
  2320. NewIgmpLink->RobustnessVariable = IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
  2321. NewIgmpLink->QueryInterval = IGMP_DEFAULT_QUERY_INTERVAL;
  2322. NewIgmpLink->MaxResponseTime = IGMP_DEFAULT_MAX_RESPONSE_TIME;
  2323. NewIgmpLink->CompatibilityMode = IgmpVersion3;
  2324. INITIALIZE_LIST_HEAD(&(NewIgmpLink->MulticastGroupList));
  2325. NewIgmpLink->Lock = KeCreateQueuedLock();
  2326. if (NewIgmpLink->Lock == NULL) {
  2327. Status = STATUS_INSUFFICIENT_RESOURCES;
  2328. goto CreateOrLookupLinkEnd;
  2329. }
  2330. //
  2331. // Determine the maximum allowed IGMP packet size based on the link.
  2332. //
  2333. LinkSizeInformation = &(Link->Properties.PacketSizeInformation);
  2334. MaxPacketSize = LinkSizeInformation->MaxPacketSize;
  2335. DataLinkEntry = Link->DataLinkEntry;
  2336. DataLinkEntry->Interface.GetPacketSizeInformation(Link->DataLinkContext,
  2337. &DataSizeInformation,
  2338. 0);
  2339. if (MaxPacketSize > DataSizeInformation.MaxPacketSize) {
  2340. MaxPacketSize = DataSizeInformation.MaxPacketSize;
  2341. }
  2342. MaxPacketSize -= (LinkSizeInformation->HeaderSize +
  2343. LinkSizeInformation->FooterSize +
  2344. DataSizeInformation.HeaderSize +
  2345. DataSizeInformation.FooterSize +
  2346. IGMP_IP4_HEADER_SIZE);
  2347. NewIgmpLink->MaxPacketSize = MaxPacketSize;
  2348. Status = NetpIgmpInitializeTimer(&(NewIgmpLink->ReportTimer),
  2349. NetpIgmpLinkReportTimeoutWorker,
  2350. NewIgmpLink);
  2351. if (!KSUCCESS(Status)) {
  2352. goto CreateOrLookupLinkEnd;
  2353. }
  2354. //
  2355. // Initialize the compatibility mode counters.
  2356. //
  2357. for (Index = 0; Index < IGMP_COMPATIBILITY_MODE_COUNT; Index += 1) {
  2358. Status = NetpIgmpInitializeTimer(
  2359. &(NewIgmpLink->CompatibilityTimer[Index]),
  2360. NetpIgmpLinkCompatibilityTimeoutWorker,
  2361. NewIgmpLink);
  2362. if (!KSUCCESS(Status)) {
  2363. goto CreateOrLookupLinkEnd;
  2364. }
  2365. }
  2366. //
  2367. // Attempt to insert the new IGMP link into the tree. If an existing link
  2368. // is found, use that one and destroy the new one.
  2369. //
  2370. SearchLink.Link = Link;
  2371. KeAcquireSharedExclusiveLockExclusive(NetIgmpLinkLock);
  2372. FoundNode = RtlRedBlackTreeSearch(&NetIgmpLinkTree, &(SearchLink.Node));
  2373. if (FoundNode == NULL) {
  2374. RtlRedBlackTreeInsert(&NetIgmpLinkTree, &(NewIgmpLink->Node));
  2375. IgmpLink = NewIgmpLink;
  2376. NewIgmpLink = NULL;
  2377. } else {
  2378. IgmpLink = RED_BLACK_TREE_VALUE(FoundNode, IGMP_LINK, Node);
  2379. }
  2380. NetpIgmpLinkAddReference(IgmpLink);
  2381. KeReleaseSharedExclusiveLockExclusive(NetIgmpLinkLock);
  2382. CreateOrLookupLinkEnd:
  2383. if (NewIgmpLink != NULL) {
  2384. NetpIgmpLinkReleaseReference(NewIgmpLink);
  2385. }
  2386. return IgmpLink;
  2387. }
  2388. VOID
  2389. NetpIgmpDestroyLink (
  2390. PIGMP_LINK IgmpLink
  2391. )
  2392. /*++
  2393. Routine Description:
  2394. This routine destroys an IGMP link and all of its resources.
  2395. Arguments:
  2396. IgmpLink - Supplies a pointer to the IGMP link to destroy.
  2397. Return Value:
  2398. None.
  2399. --*/
  2400. {
  2401. ULONG Index;
  2402. ASSERT(IgmpLink->ReferenceCount == 0);
  2403. ASSERT(LIST_EMPTY(&(IgmpLink->MulticastGroupList)) != FALSE);
  2404. NetpIgmpDestroyTimer(&(IgmpLink->ReportTimer));
  2405. for (Index = 0; Index < IGMP_COMPATIBILITY_MODE_COUNT; Index += 1) {
  2406. NetpIgmpDestroyTimer(&(IgmpLink->CompatibilityTimer[Index]));
  2407. }
  2408. if (IgmpLink->Lock != NULL) {
  2409. KeDestroyQueuedLock(IgmpLink->Lock);
  2410. }
  2411. NetLinkReleaseReference(IgmpLink->Link);
  2412. MmFreePagedPool(IgmpLink);
  2413. return;
  2414. }
  2415. PIGMP_LINK
  2416. NetpIgmpLookupLink (
  2417. PNET_LINK Link
  2418. )
  2419. /*++
  2420. Routine Description:
  2421. This routine finds an IGMP link associated with the given network link. The
  2422. caller is expected to release a reference on the IGMP link.
  2423. Arguments:
  2424. Link - Supplies a pointer to the network link, which is used to look up the
  2425. IGMP link.
  2426. Return Value:
  2427. Returns a pointer to the matching IGMP link on success or NULL on failure.
  2428. --*/
  2429. {
  2430. PRED_BLACK_TREE_NODE FoundNode;
  2431. PIGMP_LINK IgmpLink;
  2432. IGMP_LINK SearchLink;
  2433. IgmpLink = NULL;
  2434. SearchLink.Link = Link;
  2435. KeAcquireSharedExclusiveLockShared(NetIgmpLinkLock);
  2436. FoundNode = RtlRedBlackTreeSearch(&NetIgmpLinkTree, &(SearchLink.Node));
  2437. if (FoundNode == NULL) {
  2438. goto FindLinkEnd;
  2439. }
  2440. IgmpLink = RED_BLACK_TREE_VALUE(FoundNode, IGMP_LINK, Node);
  2441. NetpIgmpLinkAddReference(IgmpLink);
  2442. FindLinkEnd:
  2443. KeReleaseSharedExclusiveLockShared(NetIgmpLinkLock);
  2444. return IgmpLink;
  2445. }
  2446. VOID
  2447. NetpIgmpLinkAddReference (
  2448. PIGMP_LINK IgmpLink
  2449. )
  2450. /*++
  2451. Routine Description:
  2452. This routine increments the reference count of an IGMP link.
  2453. Arguments:
  2454. IgmpLink - Supplies a pointer to the IGMP link.
  2455. Return Value:
  2456. None.
  2457. --*/
  2458. {
  2459. ULONG OldReferenceCount;
  2460. OldReferenceCount = RtlAtomicAdd32(&(IgmpLink->ReferenceCount), 1);
  2461. ASSERT(OldReferenceCount < 0x10000000);
  2462. return;
  2463. }
  2464. VOID
  2465. NetpIgmpLinkReleaseReference (
  2466. PIGMP_LINK IgmpLink
  2467. )
  2468. /*++
  2469. Routine Description:
  2470. This routine releases a reference on an IGMP link.
  2471. Arguments:
  2472. IgmpLink - Supplies a pointer to the IGMP link.
  2473. Return Value:
  2474. None.
  2475. --*/
  2476. {
  2477. ULONG OldReferenceCount;
  2478. //
  2479. // Acquire the tree lock exclusively before decrementing the reference
  2480. // count. This is necessary to make the decrement and removal from the tree
  2481. // atomic.
  2482. //
  2483. KeAcquireSharedExclusiveLockExclusive(NetIgmpLinkLock);
  2484. OldReferenceCount = RtlAtomicAdd32(&(IgmpLink->ReferenceCount), (ULONG)-1);
  2485. ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x10000000));
  2486. //
  2487. // If the second reference was just released, then the last references is
  2488. // from creation. No multicast groups have a reference on the link and as
  2489. // the tree lock is held exclusively, no other threads have references on
  2490. // the link. Therefore, the link can be removed from the tree.
  2491. //
  2492. if (OldReferenceCount == 2) {
  2493. ASSERT(LIST_EMPTY(&(IgmpLink->MulticastGroupList)) != FALSE);
  2494. ASSERT(IgmpLink->GroupCount == 0);
  2495. RtlRedBlackTreeRemove(&NetIgmpLinkTree, &(IgmpLink->Node));
  2496. IgmpLink->Node.Parent = NULL;
  2497. KeReleaseSharedExclusiveLockExclusive(NetIgmpLinkLock);
  2498. NetpIgmpLinkReleaseReference(IgmpLink);
  2499. } else {
  2500. KeReleaseSharedExclusiveLockExclusive(NetIgmpLinkLock);
  2501. if (OldReferenceCount == 1) {
  2502. NetpIgmpDestroyLink(IgmpLink);
  2503. }
  2504. }
  2505. return;
  2506. }
  2507. COMPARISON_RESULT
  2508. NetpIgmpCompareLinkEntries (
  2509. PRED_BLACK_TREE Tree,
  2510. PRED_BLACK_TREE_NODE FirstNode,
  2511. PRED_BLACK_TREE_NODE SecondNode
  2512. )
  2513. /*++
  2514. Routine Description:
  2515. This routine compares two Red-Black tree nodes.
  2516. Arguments:
  2517. Tree - Supplies a pointer to the Red-Black tree that owns both nodes.
  2518. FirstNode - Supplies a pointer to the left side of the comparison.
  2519. SecondNode - Supplies a pointer to the second side of the comparison.
  2520. Return Value:
  2521. Same if the two nodes have the same value.
  2522. Ascending if the first node is less than the second node.
  2523. Descending if the second node is less than the first node.
  2524. --*/
  2525. {
  2526. PIGMP_LINK FirstIgmpLink;
  2527. PIGMP_LINK SecondIgmpLink;
  2528. FirstIgmpLink = RED_BLACK_TREE_VALUE(FirstNode, IGMP_LINK, Node);
  2529. SecondIgmpLink = RED_BLACK_TREE_VALUE(SecondNode, IGMP_LINK, Node);
  2530. if (FirstIgmpLink->Link == SecondIgmpLink->Link) {
  2531. return ComparisonResultSame;
  2532. } else if (FirstIgmpLink->Link < SecondIgmpLink->Link) {
  2533. return ComparisonResultAscending;
  2534. }
  2535. return ComparisonResultDescending;
  2536. }
  2537. PIGMP_MULTICAST_GROUP
  2538. NetpIgmpCreateGroup (
  2539. PIGMP_LINK IgmpLink,
  2540. PIP4_ADDRESS GroupAddress
  2541. )
  2542. /*++
  2543. Routine Description:
  2544. This routine creats an IGMP multicast group structure.
  2545. Arguments:
  2546. IgmpLink - Supplies a pointer to the IGMP link to which the multicast group
  2547. will belong.
  2548. GroupAddress - Supplies a pointer to the IPv4 multicast address for the
  2549. group.
  2550. Return Value:
  2551. Returns a pointer to the newly allocated multicast group.
  2552. --*/
  2553. {
  2554. PIGMP_MULTICAST_GROUP Group;
  2555. KSTATUS Status;
  2556. Group = MmAllocatePagedPool(sizeof(IGMP_MULTICAST_GROUP),
  2557. IGMP_ALLOCATION_TAG);
  2558. if (Group == NULL) {
  2559. Status = STATUS_INSUFFICIENT_RESOURCES;
  2560. goto CreateGroupEnd;
  2561. }
  2562. RtlZeroMemory(Group, sizeof(IGMP_MULTICAST_GROUP));
  2563. Group->ReferenceCount = 1;
  2564. Group->JoinCount = 1;
  2565. NetpIgmpLinkAddReference(IgmpLink);
  2566. Group->IgmpLink = IgmpLink;
  2567. Group->Address = GroupAddress->Address;
  2568. Status = NetpIgmpInitializeTimer(&(Group->Timer),
  2569. NetpIgmpGroupTimeoutWorker,
  2570. Group);
  2571. if (!KSUCCESS(Status)) {
  2572. goto CreateGroupEnd;
  2573. }
  2574. CreateGroupEnd:
  2575. if (!KSUCCESS(Status)) {
  2576. if (Group != NULL) {
  2577. NetpIgmpDestroyGroup(Group);
  2578. Group = NULL;
  2579. }
  2580. }
  2581. return Group;
  2582. }
  2583. VOID
  2584. NetpIgmpDestroyGroup (
  2585. PIGMP_MULTICAST_GROUP Group
  2586. )
  2587. /*++
  2588. Routine Description:
  2589. This routine destroys all the resources for the given multicast group.
  2590. Arguments:
  2591. Group - Supplies a pointer to the group to destroy.
  2592. Return Value:
  2593. None.
  2594. --*/
  2595. {
  2596. ASSERT(Group->JoinCount == 0);
  2597. NetpIgmpDestroyTimer(&(Group->Timer));
  2598. NetpIgmpLinkReleaseReference(Group->IgmpLink);
  2599. MmFreePagedPool(Group);
  2600. return;
  2601. }
  2602. PIGMP_MULTICAST_GROUP
  2603. NetpIgmpLookupGroup (
  2604. PIGMP_LINK IgmpLink,
  2605. PIP4_ADDRESS GroupAddress
  2606. )
  2607. /*++
  2608. Routine Description:
  2609. This routine finds a multicast group with the given address that the given
  2610. link has joined. It takes a reference on the found group.
  2611. Arguments:
  2612. IgmpLink - Supplies a pointer to the IGMP link that owns the group to find.
  2613. GroupAddress - Supplies a pointer to the IPv4 multicast address of the
  2614. group.
  2615. Return Value:
  2616. Returns a pointer to a multicast group on success or NULL on failure.
  2617. --*/
  2618. {
  2619. PLIST_ENTRY CurrentEntry;
  2620. PIGMP_MULTICAST_GROUP Group;
  2621. ASSERT(KeIsQueuedLockHeld(IgmpLink->Lock) != FALSE);
  2622. CurrentEntry = IgmpLink->MulticastGroupList.Next;
  2623. while (CurrentEntry != &(IgmpLink->MulticastGroupList)) {
  2624. Group = LIST_VALUE(CurrentEntry, IGMP_MULTICAST_GROUP, ListEntry);
  2625. if (Group->Address == GroupAddress->Address) {
  2626. NetpIgmpGroupAddReference(Group);
  2627. return Group;
  2628. }
  2629. CurrentEntry = CurrentEntry->Next;
  2630. }
  2631. return NULL;
  2632. }
  2633. VOID
  2634. NetpIgmpGroupAddReference (
  2635. PIGMP_MULTICAST_GROUP Group
  2636. )
  2637. /*++
  2638. Routine Description:
  2639. This routine increments the reference count of an IGMP multicast group.
  2640. Arguments:
  2641. Group - Supplies a pointer to the IGMP multicast group.
  2642. Return Value:
  2643. None.
  2644. --*/
  2645. {
  2646. ULONG OldReferenceCount;
  2647. OldReferenceCount = RtlAtomicAdd32(&(Group->ReferenceCount), 1);
  2648. ASSERT(OldReferenceCount < 0x10000000);
  2649. return;
  2650. }
  2651. VOID
  2652. NetpIgmpGroupReleaseReference (
  2653. PIGMP_MULTICAST_GROUP Group
  2654. )
  2655. /*++
  2656. Routine Description:
  2657. This routine releases a reference on an IGMP multicast group.
  2658. Arguments:
  2659. Group - Supplies a pointer to the IGMP multicast group.
  2660. Return Value:
  2661. None.
  2662. --*/
  2663. {
  2664. ULONG OldReferenceCount;
  2665. OldReferenceCount = RtlAtomicAdd32(&(Group->ReferenceCount), (ULONG)-1);
  2666. ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x10000000));
  2667. if (OldReferenceCount == 1) {
  2668. NetpIgmpDestroyGroup(Group);
  2669. }
  2670. return;
  2671. }
  2672. KSTATUS
  2673. NetpIgmpInitializeTimer (
  2674. PIGMP_TIMER Timer,
  2675. PWORK_ITEM_ROUTINE WorkRoutine,
  2676. PVOID WorkParameter
  2677. )
  2678. /*++
  2679. Routine Description:
  2680. This routine initializes the given IGMP timer, setting up its timer, DPC,
  2681. and work item.
  2682. Arguments:
  2683. Timer - Supplies a pointer to the IGMP timer to initialize.
  2684. WorkRoutine - Supplies a pointer to the routine that runs when the work
  2685. item is scheduled.
  2686. WorkParameter - Supplies a pointer that is passed to the work routine when
  2687. it is invoked.
  2688. Return Value:
  2689. Status code.
  2690. --*/
  2691. {
  2692. KSTATUS Status;
  2693. Timer->Timer = KeCreateTimer(IGMP_ALLOCATION_TAG);
  2694. if (Timer->Timer == NULL) {
  2695. Status = STATUS_INSUFFICIENT_RESOURCES;
  2696. goto InitializeTimerEnd;
  2697. }
  2698. Timer->Dpc = KeCreateDpc(NetpIgmpTimerDpcRoutine, Timer);
  2699. if (Timer->Dpc == NULL) {
  2700. Status = STATUS_INSUFFICIENT_RESOURCES;
  2701. goto InitializeTimerEnd;
  2702. }
  2703. Timer->WorkItem = KeCreateWorkItem(NULL,
  2704. WorkPriorityNormal,
  2705. WorkRoutine,
  2706. WorkParameter,
  2707. IGMP_ALLOCATION_TAG);
  2708. if (Timer->WorkItem == NULL) {
  2709. Status = STATUS_INSUFFICIENT_RESOURCES;
  2710. goto InitializeTimerEnd;
  2711. }
  2712. Status = STATUS_SUCCESS;
  2713. InitializeTimerEnd:
  2714. if (!KSUCCESS(Status)) {
  2715. NetpIgmpDestroyTimer(Timer);
  2716. }
  2717. return Status;
  2718. }
  2719. VOID
  2720. NetpIgmpDestroyTimer (
  2721. PIGMP_TIMER Timer
  2722. )
  2723. /*++
  2724. Routine Description:
  2725. This routine destroys all the resources of an IGMP timer. It does not
  2726. release the structure itself, as it is ususally embedded within another
  2727. structure.
  2728. Arguments:
  2729. Timer - Supplies a pointer to an IGMP timer to destroy.
  2730. Return Value:
  2731. None.
  2732. --*/
  2733. {
  2734. if (Timer->Timer != NULL) {
  2735. KeDestroyTimer(Timer->Timer);
  2736. }
  2737. if (Timer->Dpc != NULL) {
  2738. KeDestroyDpc(Timer->Dpc);
  2739. }
  2740. if (Timer->WorkItem != NULL) {
  2741. KeDestroyWorkItem(Timer->WorkItem);
  2742. }
  2743. return;
  2744. }
  2745. BOOL
  2746. NetpIgmpIsReportableAddress (
  2747. ULONG GroupAddress
  2748. )
  2749. /*++
  2750. Routine Description:
  2751. This routine determines whether or not the given group address should be
  2752. reported.
  2753. Arguments:
  2754. GroupAddress - Supplies a pointer to the group address to check.
  2755. Return Value:
  2756. Returns TRUE if the address should be reported or FALSE otherwise.
  2757. --*/
  2758. {
  2759. if (GroupAddress == IGMP_ALL_SYSTEMS_ADDRESS) {
  2760. return FALSE;
  2761. }
  2762. return TRUE;
  2763. }