3 Copyright (c) 2004, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #define RAND_MAX 0x10000
21 // Definitions for internet group management protocol version 2 message
22 // structure Per RFC 2236, November 1997
24 UINT8 RouterAlertOption
[4] = { 0x80 | 20, 4, 0, 0 };
25 IPV4_ADDR AllRoutersGroup
= { { 224, 0, 0, 2 } };
27 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
30 PXE_BASECODE_DEVICE
*Private
,
34 if (Private
== NULL
) {
38 if (TimerId
>= Private
->MCastGroupCount
) {
42 if (Private
->IgmpGroupEvent
[TimerId
] == NULL
) {
46 gBS
->CloseEvent (Private
->IgmpGroupEvent
[TimerId
]);
47 Private
->IgmpGroupEvent
[TimerId
] = NULL
;
50 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
58 PXE_BASECODE_DEVICE
*Private
,
65 if (Private
== NULL
) {
69 if (TimerId
>= Private
->MCastGroupCount
) {
73 if (Private
->IgmpGroupEvent
[TimerId
] != NULL
) {
74 gBS
->CloseEvent (Private
->IgmpGroupEvent
[TimerId
]);
77 EfiStatus
= gBS
->CreateEvent (
82 &Private
->IgmpGroupEvent
[TimerId
]
85 if (EFI_ERROR (EfiStatus
)) {
86 Private
->IgmpGroupEvent
[TimerId
] = NULL
;
90 EfiStatus
= gBS
->SetTimer (
91 Private
->IgmpGroupEvent
[TimerId
],
93 MaxRespTime
* 1000000 + Random (Private
) % RAND_MAX
96 if (EFI_ERROR (EfiStatus
)) {
97 gBS
->CloseEvent (Private
->IgmpGroupEvent
[TimerId
]);
98 Private
->IgmpGroupEvent
[TimerId
] = NULL
;
102 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
110 PXE_BASECODE_DEVICE
*Private
,
115 Private
->IgmpMessage
.Type
= Type
;
116 Private
->IgmpMessage
.MaxRespTime
= 0;
117 Private
->IgmpMessage
.Checksum
= 0;
118 Private
->IgmpMessage
.GroupAddress
= Private
->MCastGroup
[GroupId
];
119 Private
->IgmpMessage
.Checksum
= IpChecksum (
120 (UINT16
*) &Private
->IgmpMessage
,
121 sizeof Private
->IgmpMessage
127 (UINT8
*) &Private
->IgmpMessage
,
128 sizeof Private
->IgmpMessage
,
131 sizeof RouterAlertOption
,
132 ((Type
== IGMP_TYPE_LEAVE_GROUP
) ? AllRoutersGroup
.L
: Private
->IgmpMessage
.GroupAddress
),
133 EFI_PXE_BASE_CODE_FUNCTION_IGMP
137 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
145 PXE_BASECODE_DEVICE
*Private
,
150 // if version 1 querier, send v1 report
154 if (Private
->Igmpv1TimeoutEvent
!= NULL
) {
155 if (!EFI_ERROR (gBS
->CheckEvent (Private
->Igmpv1TimeoutEvent
))) {
156 gBS
->CloseEvent (Private
->Igmpv1TimeoutEvent
);
157 Private
->Igmpv1TimeoutEvent
= NULL
;
158 Private
->UseIgmpv1Reporting
= TRUE
;
162 Type
= (UINT8
) (Private
->UseIgmpv1Reporting
? IGMP_TYPE_V1REPORT
: IGMP_TYPE_REPORT
);
164 SendIgmpMessage (Private
, Type
, GroupId
);
165 ClearGroupTimer (Private
, GroupId
);
168 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
176 PXE_BASECODE_DEVICE
*Private
181 if (Private
== NULL
) {
185 for (GroupId
= 0; GroupId
< Private
->MCastGroupCount
; ++GroupId
) {
186 if (Private
->IgmpGroupEvent
[GroupId
] == NULL
) {
190 if (!EFI_ERROR (gBS
->CheckEvent (Private
->IgmpGroupEvent
[GroupId
]))) {
194 ReportIgmp (Private
, GroupId
);
199 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
203 @return 0 := Group not found
204 @return other := Group ID#
209 PXE_BASECODE_DEVICE
*Private
,
215 for (GroupId
= 0; GroupId
< Private
->MCastGroupCount
; ++GroupId
) {
216 if (Private
->MCastGroup
[GroupId
] == GroupAddress
) {
224 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
232 PXE_BASECODE_DEVICE
*Private
,
233 EFI_IP_ADDRESS
*GroupPtr
238 Grp
= *(UINT32
*) GroupPtr
;
241 // see if we already have it or if we can't take anymore
243 if (FindMulticastGroup (Private
, Grp
) || Private
->MCastGroupCount
== MAX_MCAST_GROUPS
) {
249 Private
->MCastGroup
[Private
->MCastGroupCount
] = Grp
;
251 ReportIgmp (Private
, Private
->MCastGroupCount
);
254 // so it will get sent again per RFC 2236
258 Private
->MCastGroupCount
++,
259 UNSOLICITED_REPORT_INTERVAL
* 10
263 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
271 PXE_BASECODE_DEVICE
*Private
,
272 EFI_IP_ADDRESS
*GroupPtr
278 Grp
= *(UINT32
*) GroupPtr
;
281 // if not in group, ignore
283 GroupId
= FindMulticastGroup (Private
, Grp
);
289 // if not v1 querrier, send leave group IGMP message
291 if (Private
->Igmpv1TimeoutEvent
!= NULL
) {
292 if (!EFI_ERROR (gBS
->CheckEvent (Private
->Igmpv1TimeoutEvent
))) {
293 gBS
->CloseEvent (Private
->Igmpv1TimeoutEvent
);
294 Private
->Igmpv1TimeoutEvent
= NULL
;
295 Private
->UseIgmpv1Reporting
= TRUE
;
297 SendIgmpMessage (Private
, IGMP_TYPE_LEAVE_GROUP
, GroupId
- 1);
301 while (GroupId
< Private
->MCastGroupCount
) {
302 Private
->MCastGroup
[GroupId
- 1] = Private
->MCastGroup
[GroupId
];
303 Private
->IgmpGroupEvent
[GroupId
- 1] = Private
->IgmpGroupEvent
[GroupId
];
307 --Private
->MCastGroupCount
;
310 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
318 PXE_BASECODE_DEVICE
*Private
,
319 IGMPV2_MESSAGE
*IgmpMessagePtr
,
323 EFI_STATUS EfiStatus
;
327 if (Private
== NULL
) {
331 if (Private
->MCastGroupCount
== 0) {
333 // if we don't belong to any multicast groups, ignore
340 if (IpChecksum ((UINT16
*) IgmpMessagePtr
, IgmpLength
)) {
342 // bad checksum - ignore packet
347 switch (IgmpMessagePtr
->Type
) {
348 case IGMP_TYPE_QUERY
:
350 // if a version 1 querier, note the fact and set max resp time
352 MaxRespTime
= IgmpMessagePtr
->MaxRespTime
;
354 if (MaxRespTime
== 0) {
355 Private
->UseIgmpv1Reporting
= TRUE
;
357 if (Private
->Igmpv1TimeoutEvent
!= NULL
) {
358 gBS
->CloseEvent (Private
->Igmpv1TimeoutEvent
);
361 EfiStatus
= gBS
->CreateEvent (
366 &Private
->Igmpv1TimeoutEvent
369 if (EFI_ERROR (EfiStatus
)) {
370 Private
->Igmpv1TimeoutEvent
= NULL
;
372 EfiStatus
= gBS
->SetTimer (
373 Private
->Igmpv1TimeoutEvent
,
375 (UINT64
) V1ROUTER_PRESENT_TIMEOUT
* 10000000
379 MaxRespTime
= IGMP_DEFAULT_MAX_RESPONSE_TIME
* 10;
382 // if a general query (!GroupAddress), set all our group timers
384 if (!IgmpMessagePtr
->GroupAddress
) {
385 for (GroupId
= 0; GroupId
< Private
->MCastGroupCount
; ++GroupId
) {
386 SetGroupTimer (Private
, GroupId
, MaxRespTime
);
390 // specific query - set only specific group
392 GroupId
= FindMulticastGroup (Private
, IgmpMessagePtr
->GroupAddress
);
395 SetGroupTimer (Private
, GroupId
- 1, MaxRespTime
);
402 // if we have a timer running for this group, clear it
404 case IGMP_TYPE_V1REPORT
:
405 case IGMP_TYPE_REPORT
:
406 GroupId
= FindMulticastGroup (Private
, IgmpMessagePtr
->GroupAddress
);
409 ClearGroupTimer (Private
, GroupId
- 1);
416 /* EOF - pxe_bc_igmp.c */