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 STATIC UINT8 RouterAlertOption
[4] = { 0x80 | 20, 4, 0, 0 };
25 STATIC IPV4_ADDR AllRoutersGroup
= { { 224, 0, 0, 2 } };
27 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
31 PXE_BASECODE_DEVICE
*Private
,
35 if (Private
== NULL
) {
39 if (TimerId
>= Private
->MCastGroupCount
) {
43 if (Private
->IgmpGroupEvent
[TimerId
] == NULL
) {
47 gBS
->CloseEvent (Private
->IgmpGroupEvent
[TimerId
]);
48 Private
->IgmpGroupEvent
[TimerId
] = NULL
;
51 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
60 PXE_BASECODE_DEVICE
*Private
,
67 if (Private
== NULL
) {
71 if (TimerId
>= Private
->MCastGroupCount
) {
75 if (Private
->IgmpGroupEvent
[TimerId
] != NULL
) {
76 gBS
->CloseEvent (Private
->IgmpGroupEvent
[TimerId
]);
79 EfiStatus
= gBS
->CreateEvent (
84 &Private
->IgmpGroupEvent
[TimerId
]
87 if (EFI_ERROR (EfiStatus
)) {
88 Private
->IgmpGroupEvent
[TimerId
] = NULL
;
92 EfiStatus
= gBS
->SetTimer (
93 Private
->IgmpGroupEvent
[TimerId
],
95 MaxRespTime
* 1000000 + Random (Private
) % RAND_MAX
98 if (EFI_ERROR (EfiStatus
)) {
99 gBS
->CloseEvent (Private
->IgmpGroupEvent
[TimerId
]);
100 Private
->IgmpGroupEvent
[TimerId
] = NULL
;
104 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
113 PXE_BASECODE_DEVICE
*Private
,
118 Private
->IgmpMessage
.Type
= Type
;
119 Private
->IgmpMessage
.MaxRespTime
= 0;
120 Private
->IgmpMessage
.Checksum
= 0;
121 Private
->IgmpMessage
.GroupAddress
= Private
->MCastGroup
[GroupId
];
122 Private
->IgmpMessage
.Checksum
= IpChecksum (
123 (UINT16
*) &Private
->IgmpMessage
,
124 sizeof Private
->IgmpMessage
130 (UINT8
*) &Private
->IgmpMessage
,
131 sizeof Private
->IgmpMessage
,
134 sizeof RouterAlertOption
,
135 ((Type
== IGMP_TYPE_LEAVE_GROUP
) ? AllRoutersGroup
.L
: Private
->IgmpMessage
.GroupAddress
),
136 EFI_PXE_BASE_CODE_FUNCTION_IGMP
140 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
149 PXE_BASECODE_DEVICE
*Private
,
154 // if version 1 querier, send v1 report
158 if (Private
->Igmpv1TimeoutEvent
!= NULL
) {
159 if (!EFI_ERROR (gBS
->CheckEvent (Private
->Igmpv1TimeoutEvent
))) {
160 gBS
->CloseEvent (Private
->Igmpv1TimeoutEvent
);
161 Private
->Igmpv1TimeoutEvent
= NULL
;
162 Private
->UseIgmpv1Reporting
= TRUE
;
166 Type
= (UINT8
) (Private
->UseIgmpv1Reporting
? IGMP_TYPE_V1REPORT
: IGMP_TYPE_REPORT
);
168 SendIgmpMessage (Private
, Type
, GroupId
);
169 ClearGroupTimer (Private
, GroupId
);
172 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
180 PXE_BASECODE_DEVICE
*Private
185 if (Private
== NULL
) {
189 for (GroupId
= 0; GroupId
< Private
->MCastGroupCount
; ++GroupId
) {
190 if (Private
->IgmpGroupEvent
[GroupId
] == NULL
) {
194 if (!EFI_ERROR (gBS
->CheckEvent (Private
->IgmpGroupEvent
[GroupId
]))) {
198 ReportIgmp (Private
, GroupId
);
203 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
207 @return 0 := Group not found
208 @return other := Group ID#
214 PXE_BASECODE_DEVICE
*Private
,
220 for (GroupId
= 0; GroupId
< Private
->MCastGroupCount
; ++GroupId
) {
221 if (Private
->MCastGroup
[GroupId
] == GroupAddress
) {
229 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
237 PXE_BASECODE_DEVICE
*Private
,
238 EFI_IP_ADDRESS
*GroupPtr
243 Grp
= *(UINT32
*) GroupPtr
;
246 // see if we already have it or if we can't take anymore
248 if (FindMulticastGroup (Private
, Grp
) || Private
->MCastGroupCount
== MAX_MCAST_GROUPS
) {
254 Private
->MCastGroup
[Private
->MCastGroupCount
] = Grp
;
256 ReportIgmp (Private
, Private
->MCastGroupCount
);
259 // so it will get sent again per RFC 2236
263 Private
->MCastGroupCount
++,
264 UNSOLICITED_REPORT_INTERVAL
* 10
268 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
276 PXE_BASECODE_DEVICE
*Private
,
277 EFI_IP_ADDRESS
*GroupPtr
283 Grp
= *(UINT32
*) GroupPtr
;
286 // if not in group, ignore
288 GroupId
= FindMulticastGroup (Private
, Grp
);
294 // if not v1 querrier, send leave group IGMP message
296 if (Private
->Igmpv1TimeoutEvent
!= NULL
) {
297 if (!EFI_ERROR (gBS
->CheckEvent (Private
->Igmpv1TimeoutEvent
))) {
298 gBS
->CloseEvent (Private
->Igmpv1TimeoutEvent
);
299 Private
->Igmpv1TimeoutEvent
= NULL
;
300 Private
->UseIgmpv1Reporting
= TRUE
;
302 SendIgmpMessage (Private
, IGMP_TYPE_LEAVE_GROUP
, GroupId
- 1);
306 while (GroupId
< Private
->MCastGroupCount
) {
307 Private
->MCastGroup
[GroupId
- 1] = Private
->MCastGroup
[GroupId
];
308 Private
->IgmpGroupEvent
[GroupId
- 1] = Private
->IgmpGroupEvent
[GroupId
];
312 --Private
->MCastGroupCount
;
315 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
323 PXE_BASECODE_DEVICE
*Private
,
324 IGMPV2_MESSAGE
*IgmpMessagePtr
,
328 EFI_STATUS EfiStatus
;
332 if (Private
== NULL
) {
336 if (Private
->MCastGroupCount
== 0) {
338 // if we don't belong to any multicast groups, ignore
345 if (IpChecksum ((UINT16
*) IgmpMessagePtr
, IgmpLength
)) {
347 // bad checksum - ignore packet
352 switch (IgmpMessagePtr
->Type
) {
353 case IGMP_TYPE_QUERY
:
355 // if a version 1 querier, note the fact and set max resp time
357 MaxRespTime
= IgmpMessagePtr
->MaxRespTime
;
359 if (MaxRespTime
== 0) {
360 Private
->UseIgmpv1Reporting
= TRUE
;
362 if (Private
->Igmpv1TimeoutEvent
!= NULL
) {
363 gBS
->CloseEvent (Private
->Igmpv1TimeoutEvent
);
366 EfiStatus
= gBS
->CreateEvent (
371 &Private
->Igmpv1TimeoutEvent
374 if (EFI_ERROR (EfiStatus
)) {
375 Private
->Igmpv1TimeoutEvent
= NULL
;
377 EfiStatus
= gBS
->SetTimer (
378 Private
->Igmpv1TimeoutEvent
,
380 (UINT64
) V1ROUTER_PRESENT_TIMEOUT
* 10000000
384 MaxRespTime
= IGMP_DEFAULT_MAX_RESPONSE_TIME
* 10;
387 // if a general query (!GroupAddress), set all our group timers
389 if (!IgmpMessagePtr
->GroupAddress
) {
390 for (GroupId
= 0; GroupId
< Private
->MCastGroupCount
; ++GroupId
) {
391 SetGroupTimer (Private
, GroupId
, MaxRespTime
);
395 // specific query - set only specific group
397 GroupId
= FindMulticastGroup (Private
, IgmpMessagePtr
->GroupAddress
);
400 SetGroupTimer (Private
, GroupId
- 1, MaxRespTime
);
407 // if we have a timer running for this group, clear it
409 case IGMP_TYPE_V1REPORT
:
410 case IGMP_TYPE_REPORT
:
411 GroupId
= FindMulticastGroup (Private
, IgmpMessagePtr
->GroupAddress
);
414 ClearGroupTimer (Private
, GroupId
- 1);
421 /* EOF - pxe_bc_igmp.c */