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