3 Copyright (c) 2006 - 2007, 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.
17 #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 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
55 PXE_BASECODE_DEVICE
*Private
,
61 Set IGMP response timeout value.
64 Private := Pointer to PxeBc interface
66 MaxRespTime := Base response timeout value in tenths of seconds
73 if (Private
== NULL
) {
77 if (TimerId
>= Private
->MCastGroupCount
) {
81 if (Private
->IgmpGroupEvent
[TimerId
] != NULL
) {
82 gBS
->CloseEvent (Private
->IgmpGroupEvent
[TimerId
]);
85 EfiStatus
= gBS
->CreateEvent (
90 &Private
->IgmpGroupEvent
[TimerId
]
93 if (EFI_ERROR (EfiStatus
)) {
94 Private
->IgmpGroupEvent
[TimerId
] = NULL
;
98 EfiStatus
= gBS
->SetTimer (
99 Private
->IgmpGroupEvent
[TimerId
],
101 MaxRespTime
* 1000000 + Random (Private
) % RAND_MAX
104 if (EFI_ERROR (EfiStatus
)) {
105 gBS
->CloseEvent (Private
->IgmpGroupEvent
[TimerId
]);
106 Private
->IgmpGroupEvent
[TimerId
] = NULL
;
110 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
114 PXE_BASECODE_DEVICE
*Private
,
123 Private := Pointer to PxeBc interface
124 Type := Message type opcode
130 Private
->IgmpMessage
.Type
= Type
;
131 Private
->IgmpMessage
.MaxRespTime
= 0;
132 Private
->IgmpMessage
.Checksum
= 0;
133 Private
->IgmpMessage
.GroupAddress
= Private
->MCastGroup
[GroupId
];
134 Private
->IgmpMessage
.Checksum
= IpChecksum (
135 (UINT16
*) &Private
->IgmpMessage
,
136 sizeof Private
->IgmpMessage
142 (UINT8
*) &Private
->IgmpMessage
,
143 sizeof Private
->IgmpMessage
,
146 sizeof RouterAlertOption
,
147 ((Type
== IGMP_TYPE_LEAVE_GROUP
) ? AllRoutersGroup
.L
: Private
->IgmpMessage
.GroupAddress
),
148 EFI_PXE_BASE_CODE_FUNCTION_IGMP
152 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
156 PXE_BASECODE_DEVICE
*Private
,
161 Send an IGMP report message.
164 Private := Pointer to PxeBc interface
171 // if version 1 querier, send v1 report
175 if (Private
->Igmpv1TimeoutEvent
!= NULL
) {
176 if (!EFI_ERROR (gBS
->CheckEvent (Private
->Igmpv1TimeoutEvent
))) {
177 gBS
->CloseEvent (Private
->Igmpv1TimeoutEvent
);
178 Private
->Igmpv1TimeoutEvent
= NULL
;
179 Private
->UseIgmpv1Reporting
= TRUE
;
183 Type
= (UINT8
) (Private
->UseIgmpv1Reporting
? IGMP_TYPE_V1REPORT
: IGMP_TYPE_REPORT
);
185 SendIgmpMessage (Private
, Type
, GroupId
);
186 ClearGroupTimer (Private
, GroupId
);
189 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
192 PXE_BASECODE_DEVICE
*Private
196 Check IGMP timers and send reports for all groups that have expired.
198 Private := Pointer to PxeBc interface
205 if (Private
== NULL
) {
209 for (GroupId
= 0; GroupId
< Private
->MCastGroupCount
; ++GroupId
) {
210 if (Private
->IgmpGroupEvent
[GroupId
] == NULL
) {
214 if (!EFI_ERROR (gBS
->CheckEvent (Private
->IgmpGroupEvent
[GroupId
]))) {
218 ReportIgmp (Private
, GroupId
);
223 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
227 PXE_BASECODE_DEVICE
*Private
,
232 Fund group ID# (index).
235 Private := Pointer to PxeBc interface
236 GroupAddress := Group multicast address
245 for (GroupId
= 0; GroupId
< Private
->MCastGroupCount
; ++GroupId
) {
246 if (Private
->MCastGroup
[GroupId
] == GroupAddress
) {
254 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
257 PXE_BASECODE_DEVICE
*Private
,
258 EFI_IP_ADDRESS
*GroupPtr
262 Join multicast group.
265 Private := Pointer to PxeBc interface
266 GroupPtr := Pointer to group mutlicast IP address.
273 Grp
= *(UINT32
*) GroupPtr
;
276 // see if we already have it or if we can't take anymore
278 if (FindMulticastGroup (Private
, Grp
) || Private
->MCastGroupCount
== MAX_MCAST_GROUPS
) {
284 Private
->MCastGroup
[Private
->MCastGroupCount
] = Grp
;
286 ReportIgmp (Private
, Private
->MCastGroupCount
);
289 // so it will get sent again per RFC 2236
293 Private
->MCastGroupCount
++,
294 UNSOLICITED_REPORT_INTERVAL
* 10
298 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
301 PXE_BASECODE_DEVICE
*Private
,
302 EFI_IP_ADDRESS
*GroupPtr
306 Leave multicast group.
309 Private := Pointer to PxeBc interface
310 GroupPtr := Mutlicast group IP address.
318 Grp
= *(UINT32
*) GroupPtr
;
321 // if not in group, ignore
323 GroupId
= FindMulticastGroup (Private
, Grp
);
329 // if not v1 querrier, send leave group IGMP message
331 if (Private
->Igmpv1TimeoutEvent
!= NULL
) {
332 if (!EFI_ERROR (gBS
->CheckEvent (Private
->Igmpv1TimeoutEvent
))) {
333 gBS
->CloseEvent (Private
->Igmpv1TimeoutEvent
);
334 Private
->Igmpv1TimeoutEvent
= NULL
;
335 Private
->UseIgmpv1Reporting
= TRUE
;
337 SendIgmpMessage (Private
, IGMP_TYPE_LEAVE_GROUP
, GroupId
- 1);
341 while (GroupId
< Private
->MCastGroupCount
) {
342 Private
->MCastGroup
[GroupId
- 1] = Private
->MCastGroup
[GroupId
];
343 Private
->IgmpGroupEvent
[GroupId
- 1] = Private
->IgmpGroupEvent
[GroupId
];
347 --Private
->MCastGroupCount
;
350 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
353 PXE_BASECODE_DEVICE
*Private
,
354 IGMPV2_MESSAGE
*IgmpMessagePtr
,
359 Handle received IGMP packet
362 Private := Pointer to PxeBc interface
363 IgmpMessagePtr := Pointer to IGMP packet
364 IgmpLength := packet length in bytes
369 EFI_STATUS EfiStatus
;
373 if (Private
== NULL
) {
377 if (Private
->MCastGroupCount
== 0) {
379 // if we don't belong to any multicast groups, ignore
386 if (IpChecksum ((UINT16
*) IgmpMessagePtr
, IgmpLength
)) {
388 // bad checksum - ignore packet
393 switch (IgmpMessagePtr
->Type
) {
394 case IGMP_TYPE_QUERY
:
396 // if a version 1 querier, note the fact and set max resp time
398 MaxRespTime
= IgmpMessagePtr
->MaxRespTime
;
400 if (MaxRespTime
== 0) {
401 Private
->UseIgmpv1Reporting
= TRUE
;
403 if (Private
->Igmpv1TimeoutEvent
!= NULL
) {
404 gBS
->CloseEvent (Private
->Igmpv1TimeoutEvent
);
407 EfiStatus
= gBS
->CreateEvent (
412 &Private
->Igmpv1TimeoutEvent
415 if (EFI_ERROR (EfiStatus
)) {
416 Private
->Igmpv1TimeoutEvent
= NULL
;
418 EfiStatus
= gBS
->SetTimer (
419 Private
->Igmpv1TimeoutEvent
,
421 (UINT64
) V1ROUTER_PRESENT_TIMEOUT
* 10000000
425 MaxRespTime
= IGMP_DEFAULT_MAX_RESPONSE_TIME
* 10;
428 // if a general query (!GroupAddress), set all our group timers
430 if (!IgmpMessagePtr
->GroupAddress
) {
431 for (GroupId
= 0; GroupId
< Private
->MCastGroupCount
; ++GroupId
) {
432 SetGroupTimer (Private
, GroupId
, MaxRespTime
);
436 // specific query - set only specific group
438 GroupId
= FindMulticastGroup (Private
, IgmpMessagePtr
->GroupAddress
);
441 SetGroupTimer (Private
, GroupId
- 1, MaxRespTime
);
448 // if we have a timer running for this group, clear it
450 case IGMP_TYPE_V1REPORT
:
451 case IGMP_TYPE_REPORT
:
452 GroupId
= FindMulticastGroup (Private
, IgmpMessagePtr
->GroupAddress
);
455 ClearGroupTimer (Private
, GroupId
- 1);
462 /* EOF - pxe_bc_igmp.c */