]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_arp.c
Add some definitions for efi event in Uefi/UefiSpec.h to follow spec.
[mirror_edk2.git] / EdkModulePkg / Universal / Network / PxeBc / Dxe / pxe_bc_arp.c
1 /*++
2
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
8
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.
11
12 Module Name:
13 pxe_bc_arp.c
14
15 Abstract:
16
17 --*/
18
19
20 #include "Bc.h"
21
22 //
23 // Definitions for ARP
24 // Per RFC 826
25 //
26 STATIC ARP_HEADER ArpHeader;
27
28 #pragma pack(1)
29 STATIC struct {
30 UINT8 MediaHeader[14];
31 ARP_HEADER ArpHeader;
32 UINT8 ArpData[64];
33 } ArpReplyPacket;
34 #pragma pack()
35
36 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
37 VOID
38 InitArpHeader (
39 VOID
40 )
41 /*++
42 Routine description:
43 Initialize ARP packet header.
44
45 Parameters:
46 none
47
48 Returns:
49 none
50
51 --*/
52 {
53 ArpHeader.HwType = HTONS (ETHERNET_ADD_SPC);
54 ArpHeader.ProtType = HTONS (ETHER_TYPE_IP);
55 ArpHeader.HwAddLen = ENET_HWADDLEN;
56 ArpHeader.ProtAddLen = IPV4_PROTADDLEN;
57 ArpHeader.OpCode = HTONS (ARP_REQUEST);
58
59 CopyMem (&ArpReplyPacket.ArpHeader, &ArpHeader, sizeof (ARP_HEADER));
60 }
61
62 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
63 VOID
64 HandleArpReceive (
65 IN PXE_BASECODE_DEVICE *Private,
66 IN ARP_PACKET *ArpPacketPtr,
67 IN VOID *MediaHeader
68 )
69 /*++
70 Routine description:
71 Process ARP packet.
72
73 Parameters:
74 Private := Pointer to PxeBc interface
75 ArpPacketPtr := Pointer to ARP packet
76 MediaHeader := Pointer to media header.
77 Returns:
78 --*/
79 {
80 EFI_PXE_BASE_CODE_MODE *PxeBcMode;
81 EFI_SIMPLE_NETWORK_MODE *SnpMode;
82 EFI_MAC_ADDRESS TmpMacAddr;
83 UINTN Index;
84 UINT8 *SrcHwAddr;
85 UINT8 *SrcPrAddr;
86 UINT8 *DstHwAddr;
87 UINT8 *DstPrAddr;
88 UINT8 *TmpPtr;
89
90 //
91 //
92 //
93 PxeBcMode = Private->EfiBc.Mode;
94 SnpMode = Private->SimpleNetwork->Mode;
95
96 //
97 // For now only ethernet addresses are supported.
98 // This will need to be updated when other media
99 // layers are supported by PxeBc, Snp and UNDI.
100 //
101 if (ArpPacketPtr->ArpHeader.HwType != HTONS (ETHERNET_ADD_SPC)) {
102 return ;
103 }
104 //
105 // For now only IP protocol addresses are supported.
106 // This will need to be updated when other protocol
107 // types are supported by PxeBc, Snp and UNDI.
108 //
109 if (ArpPacketPtr->ArpHeader.ProtType != HTONS (ETHER_TYPE_IP)) {
110 return ;
111 }
112 //
113 // For now only SNP hardware address sizes are supported.
114 //
115 if (ArpPacketPtr->ArpHeader.HwAddLen != SnpMode->HwAddressSize) {
116 return ;
117 }
118 //
119 // For now only PxeBc protocol address sizes are supported.
120 //
121 if (ArpPacketPtr->ArpHeader.ProtAddLen != Private->IpLength) {
122 return ;
123 }
124 //
125 // Ignore out of range opcodes
126 //
127 switch (ArpPacketPtr->ArpHeader.OpCode) {
128 case HTONS (ARP_REPLY):
129 case HTONS (ARP_REQUEST):
130 break;
131
132 default:
133 return ;
134 }
135 //
136 // update entry in our ARP cache if we have it
137 //
138 SrcHwAddr = (UINT8 *) &ArpPacketPtr->SrcHardwareAddr;
139 SrcPrAddr = SrcHwAddr + SnpMode->HwAddressSize;
140
141 for (Index = 0; Index < PxeBcMode->ArpCacheEntries; ++Index) {
142 if (CompareMem (
143 &PxeBcMode->ArpCache[Index].IpAddr,
144 SrcPrAddr,
145 Private->IpLength
146 )) {
147 continue;
148 }
149
150 CopyMem (
151 &PxeBcMode->ArpCache[Index].MacAddr,
152 SrcHwAddr,
153 SnpMode->HwAddressSize
154 );
155
156 break;
157 }
158 //
159 // Done if ARP packet was not for us.
160 //
161 DstHwAddr = SrcPrAddr + Private->IpLength;
162 DstPrAddr = DstHwAddr + SnpMode->HwAddressSize;
163
164 if (CompareMem (DstPrAddr, &PxeBcMode->StationIp, Private->IpLength)) {
165 return ;
166 //
167 // not for us
168 //
169 }
170 //
171 // for us - if we did not update entry, add it
172 //
173 if (Index == PxeBcMode->ArpCacheEntries) {
174 //
175 // if we have a full table, get rid of oldest
176 //
177 if (Index == PXE_ARP_CACHE_SIZE) {
178 Index = Private->OldestArpEntry;
179
180 if (++Private->OldestArpEntry == PXE_ARP_CACHE_SIZE) {
181 Private->OldestArpEntry = 0;
182 }
183 } else {
184 ++PxeBcMode->ArpCacheEntries;
185 }
186
187 CopyMem (
188 &PxeBcMode->ArpCache[Index].MacAddr,
189 SrcHwAddr,
190 SnpMode->HwAddressSize
191 );
192
193 CopyMem (
194 &PxeBcMode->ArpCache[Index].IpAddr,
195 SrcPrAddr,
196 Private->IpLength
197 );
198 }
199 //
200 // if this is not a request or we don't yet have an IP, finished
201 //
202 if (ArpPacketPtr->ArpHeader.OpCode != HTONS (ARP_REQUEST) || !Private->GoodStationIp) {
203 return ;
204 }
205 //
206 // Assemble ARP reply.
207 //
208 //
209 // Create media header. [ dest mac | src mac | prot ]
210 //
211 CopyMem (
212 &ArpReplyPacket.MediaHeader[0],
213 SrcHwAddr,
214 SnpMode->HwAddressSize
215 );
216
217 CopyMem (
218 &ArpReplyPacket.MediaHeader[SnpMode->HwAddressSize],
219 &SnpMode->CurrentAddress,
220 SnpMode->HwAddressSize
221 );
222
223 CopyMem (
224 &ArpReplyPacket.MediaHeader[2 * SnpMode->HwAddressSize],
225 &((UINT8 *) MediaHeader)[2 * SnpMode->HwAddressSize],
226 sizeof (UINT16)
227 );
228
229 //
230 // ARP reply header is almost filled in,
231 // just insert the correct opcode.
232 //
233 ArpReplyPacket.ArpHeader.OpCode = HTONS (ARP_REPLY);
234
235 //
236 // Now fill in ARP data. [ src mac | src prot | dest mac | dest prot ]
237 //
238 TmpPtr = ArpReplyPacket.ArpData;
239 CopyMem (TmpPtr, &SnpMode->CurrentAddress, SnpMode->HwAddressSize);
240
241 TmpPtr += SnpMode->HwAddressSize;
242 CopyMem (TmpPtr, &PxeBcMode->StationIp, Private->IpLength);
243
244 TmpPtr += Private->IpLength;
245 CopyMem (TmpPtr, SrcHwAddr, SnpMode->HwAddressSize);
246
247 TmpPtr += SnpMode->HwAddressSize;
248 CopyMem (TmpPtr, SrcPrAddr, Private->IpLength);
249
250 //
251 // Now send out the ARP reply.
252 //
253 CopyMem (&TmpMacAddr, SrcHwAddr, sizeof (EFI_MAC_ADDRESS));
254
255 SendPacket (
256 Private,
257 &ArpReplyPacket.MediaHeader,
258 &ArpReplyPacket.ArpHeader,
259 sizeof (ARP_HEADER) + 2 * (Private->IpLength + SnpMode->HwAddressSize),
260 &TmpMacAddr,
261 PXE_PROTOCOL_ETHERNET_ARP,
262 EFI_PXE_BASE_CODE_FUNCTION_ARP
263 );
264
265 //
266 // Give time (100 microseconds) for ARP reply to get onto wire.
267 //
268 gBS->Stall (1000);
269 }
270
271 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
272 BOOLEAN
273 GetHwAddr (
274 IN PXE_BASECODE_DEVICE *Private,
275 IN EFI_IP_ADDRESS *ProtocolAddrPtr,
276 OUT EFI_MAC_ADDRESS *HardwareAddrPtr
277 )
278 /*++
279 Routine description:
280 Locate IP address in ARP cache and return MAC address.
281
282 Parameters:
283 Private := Pointer to PxeBc interface
284 ProtocolAddrPtr := Pointer to IP address
285 HardwareAddrPtr := Pointer to MAC address storage
286
287 Returns:
288 TRUE := If IP address was found and MAC address was stored
289 FALSE := If IP address was not found
290 --*/
291 {
292 EFI_PXE_BASE_CODE_MODE *PxeBcMode;
293 UINTN HardwareAddrLength;
294 UINTN Index;
295
296 PxeBcMode = Private->EfiBc.Mode;
297 HardwareAddrLength = Private->SimpleNetwork->Mode->HwAddressSize;
298
299 for (Index = 0; Index < PxeBcMode->ArpCacheEntries; ++Index) {
300 if (!CompareMem (
301 ProtocolAddrPtr,
302 &PxeBcMode->ArpCache[Index].IpAddr,
303 Private->IpLength
304 )) {
305 CopyMem (
306 HardwareAddrPtr,
307 &PxeBcMode->ArpCache[Index].MacAddr,
308 HardwareAddrLength
309 );
310
311 return TRUE;
312 }
313 }
314
315 return FALSE;
316 }
317
318 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
319 STATIC
320 EFI_STATUS
321 SendRequest (
322 IN PXE_BASECODE_DEVICE *Private,
323 IN EFI_IP_ADDRESS *ProtocolAddrPtr,
324 IN EFI_MAC_ADDRESS *HardwareAddrPtr
325 )
326 /*++
327 Routine description:
328 Transmit ARP request packet
329
330 Parameters:
331 Private := Pointer to PxeBc interface
332 ProtocolAddrPtr := Pointer IP address to find
333 HardwareAddrPtr := Pointer to MAC address to find
334
335 Returns:
336 EFI_SUCCESS := ARP request sent
337 other := ARP request could not be sent
338 --*/
339 {
340 EFI_PXE_BASE_CODE_MODE *PxeBcMode;
341 EFI_SIMPLE_NETWORK_MODE *SnpMode;
342 ARP_PACKET *ArpPacket;
343 UINTN HardwareAddrLength;
344 UINT8 *SrcProtocolAddrPtr;
345 UINT8 *DestHardwareAddrptr;
346 UINT8 *DestProtocolAddrPtr;
347
348 //
349 //
350 //
351 PxeBcMode = Private->EfiBc.Mode;
352 SnpMode = Private->SimpleNetwork->Mode;
353 HardwareAddrLength = SnpMode->HwAddressSize;
354
355 //
356 // Allocate ARP buffer
357 //
358 if (Private->ArpBuffer == NULL) {
359 Private->ArpBuffer = AllocatePool (SnpMode->MediaHeaderSize + sizeof (ARP_PACKET));
360 if (Private->ArpBuffer == NULL) {
361 return EFI_OUT_OF_RESOURCES;
362 }
363 }
364
365 ArpPacket = (VOID *) (Private->ArpBuffer + SnpMode->MediaHeaderSize);
366
367 //
368 // for now, only handle one kind of hw and pr address
369 //
370 ArpPacket->ArpHeader = ArpHeader;
371 ArpPacket->ArpHeader.HwAddLen = (UINT8) HardwareAddrLength;
372 ArpPacket->ArpHeader.ProtAddLen = (UINT8) Private->IpLength;
373
374 //
375 // rest more generic
376 //
377 SrcProtocolAddrPtr = (UINT8 *) (&ArpPacket->SrcHardwareAddr) + HardwareAddrLength;
378 DestHardwareAddrptr = SrcProtocolAddrPtr + Private->IpLength;
379 DestProtocolAddrPtr = DestHardwareAddrptr + HardwareAddrLength;
380
381 CopyMem (DestProtocolAddrPtr, ProtocolAddrPtr, Private->IpLength);
382 CopyMem (DestHardwareAddrptr, HardwareAddrPtr, HardwareAddrLength);
383 CopyMem (SrcProtocolAddrPtr, &PxeBcMode->StationIp, Private->IpLength);
384 CopyMem (
385 &ArpPacket->SrcHardwareAddr,
386 &SnpMode->CurrentAddress,
387 HardwareAddrLength
388 );
389
390 return SendPacket (
391 Private,
392 Private->ArpBuffer,
393 ArpPacket,
394 sizeof (ARP_HEADER) + ((Private->IpLength + HardwareAddrLength) << 1),
395 &SnpMode->BroadcastAddress,
396 PXE_PROTOCOL_ETHERNET_ARP,
397 EFI_PXE_BASE_CODE_FUNCTION_ARP
398 );
399 }
400
401 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
402
403 //
404 // check for address - if not there, send ARP request, wait and check again
405 // not how it would be done in a full system
406 //
407 #define ARP_REQUEST_TIMEOUT_MS 500 // try for half a second
408
409 ////////////////////////////////////////////////////////////
410 //
411 // BC Arp Routine
412 //
413 EFI_STATUS
414 EFIAPI
415 BcArp (
416 IN EFI_PXE_BASE_CODE_PROTOCOL * This,
417 IN EFI_IP_ADDRESS * ProtocolAddrPtr,
418 OUT EFI_MAC_ADDRESS * HardwareAddrPtr OPTIONAL
419 )
420 /*++
421 Routine description:
422 PxeBc ARP API.
423
424 Parameters:
425 This := Pointer to PxeBc interface
426 ProtocolAddrPtr := Pointer to IP address to find
427 HardwareAddrPtr := Pointer to MAC address found.
428
429 Returns:
430 --*/
431 {
432 EFI_MAC_ADDRESS Mac;
433 EFI_STATUS StatCode;
434 PXE_BASECODE_DEVICE *Private;
435
436 //
437 // Lock the instance data and make sure started
438 //
439 StatCode = EFI_SUCCESS;
440
441 if (This == NULL) {
442 DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));
443 return EFI_INVALID_PARAMETER;
444 }
445
446 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
447
448 if (Private == NULL) {
449 DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
450 return EFI_INVALID_PARAMETER;
451 }
452
453 EfiAcquireLock (&Private->Lock);
454
455 if (This->Mode == NULL || !This->Mode->Started) {
456 DEBUG ((EFI_D_ERROR, "BC was not started."));
457 EfiReleaseLock (&Private->Lock);
458 return EFI_NOT_STARTED;
459 }
460
461 DEBUG ((EFI_D_INFO, "\nBcArp()"));
462
463 //
464 // Issue BC command
465 //
466 if (ProtocolAddrPtr == NULL) {
467 DEBUG (
468 (EFI_D_INFO,
469 "\nBcArp() Exit #1 %Xh (%r)",
470 EFI_INVALID_PARAMETER,
471 EFI_INVALID_PARAMETER)
472 );
473
474 EfiReleaseLock (&Private->Lock);
475 return EFI_INVALID_PARAMETER;
476 }
477
478 if (HardwareAddrPtr == NULL) {
479 HardwareAddrPtr = &Mac;
480 }
481
482 ZeroMem (HardwareAddrPtr, Private->SimpleNetwork->Mode->HwAddressSize);
483
484 if (GetHwAddr (Private, ProtocolAddrPtr, HardwareAddrPtr)) {
485 DEBUG (
486 (EFI_D_INFO,
487 "\nBcArp() Exit #2 %Xh (%r)",
488 EFI_SUCCESS,
489 EFI_SUCCESS)
490 );
491
492 EfiReleaseLock (&Private->Lock);
493 return EFI_SUCCESS;
494 }
495
496 StatCode = DoArp (Private, ProtocolAddrPtr, HardwareAddrPtr);
497
498 DEBUG ((EFI_D_INFO, "\nBcArp() Exit #3 %Xh (%r)", StatCode, StatCode));
499
500 EfiReleaseLock (&Private->Lock);
501 return StatCode;
502 }
503
504 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
505 EFI_STATUS
506 DoArp (
507 IN PXE_BASECODE_DEVICE *Private,
508 IN EFI_IP_ADDRESS *ProtocolAddrPtr,
509 OUT EFI_MAC_ADDRESS *HardwareAddrPtr
510 )
511 /*++
512 Routine description:
513 Internal ARP implementation.
514
515 Parameters:
516 Private := Pointer to PxeBc interface
517 ProtocolAddrPtr := Pointer to IP address to find
518 HardwareAddrPtr := Pointer to MAC address found
519
520 Returns:
521 EFI_SUCCESS := MAC address found
522 other := MAC address could not be found
523 --*/
524 {
525 EFI_STATUS StatCode;
526 EFI_EVENT TimeoutEvent;
527 UINTN HeaderSize;
528 UINTN BufferSize;
529 UINT16 Protocol;
530
531 DEBUG ((EFI_D_INFO, "\nDoArp()"));
532
533 //
534 //
535 //
536 StatCode = SendRequest (Private, ProtocolAddrPtr, HardwareAddrPtr);
537
538 if (EFI_ERROR (StatCode)) {
539 DEBUG ((EFI_D_INFO, "\nDoArp() Exit #1 %Xh (%r)", StatCode, StatCode));
540 return StatCode;
541 }
542 //
543 //
544 //
545 StatCode = gBS->CreateEvent (
546 EVT_TIMER,
547 TPL_CALLBACK,
548 NULL,
549 NULL,
550 &TimeoutEvent
551 );
552
553 if (EFI_ERROR (StatCode)) {
554 return StatCode;
555 }
556
557 StatCode = gBS->SetTimer (
558 TimeoutEvent,
559 TimerRelative,
560 ARP_REQUEST_TIMEOUT_MS * 10000
561 );
562
563 if (EFI_ERROR (StatCode)) {
564 gBS->CloseEvent (TimeoutEvent);
565 return StatCode;
566 }
567 //
568 //
569 //
570 for (;;) {
571 StatCode = WaitForReceive (
572 Private,
573 EFI_PXE_BASE_CODE_FUNCTION_ARP,
574 TimeoutEvent,
575 &HeaderSize,
576 &BufferSize,
577 &Protocol
578 );
579
580 if (EFI_ERROR (StatCode)) {
581 break;
582 }
583
584 if (Protocol != PXE_PROTOCOL_ETHERNET_ARP) {
585 continue;
586 }
587
588 HandleArpReceive (
589 Private,
590 (ARP_PACKET *) (Private->ReceiveBufferPtr + HeaderSize),
591 Private->ReceiveBufferPtr
592 );
593
594 if (GetHwAddr (Private, ProtocolAddrPtr, HardwareAddrPtr)) {
595 break;
596 }
597 }
598
599 DEBUG (
600 (EFI_D_INFO,
601 "\nDoArp() Exit #2 %Xh, (%r)",
602 StatCode,
603 StatCode)
604 );
605
606 gBS->CloseEvent (TimeoutEvent);
607
608 return StatCode;
609 }
610
611 /* eof - pxe_bc_arp.c */