]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/PxeBcDxe/Pxe_bc_arp.c
Import ArpDxe, Dhcp4Dxe, Ip4Dxe, Mtftp4Dxe, PxeBcDxe and PxeDhcp4Dxe.
[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 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
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 STATIC
311 EFI_STATUS
312 SendRequest (
313 IN PXE_BASECODE_DEVICE *Private,
314 IN EFI_IP_ADDRESS *ProtocolAddrPtr,
315 IN EFI_MAC_ADDRESS *HardwareAddrPtr
316 )
317 {
318 EFI_PXE_BASE_CODE_MODE *PxeBcMode;
319 EFI_SIMPLE_NETWORK_MODE *SnpMode;
320 ARP_PACKET *ArpPacket;
321 EFI_STATUS Status;
322 UINTN HardwareAddrLength;
323 UINT8 *SrcProtocolAddrPtr;
324 UINT8 *DestHardwareAddrptr;
325 UINT8 *DestProtocolAddrPtr;
326
327 //
328 //
329 //
330 PxeBcMode = Private->EfiBc.Mode;
331 SnpMode = Private->SimpleNetwork->Mode;
332 HardwareAddrLength = SnpMode->HwAddressSize;
333
334 //
335 // Allocate ARP buffer
336 //
337 if (Private->ArpBuffer == NULL) {
338 Status = gBS->AllocatePool (
339 EfiBootServicesData,
340 SnpMode->MediaHeaderSize + sizeof (ARP_PACKET),
341 &Private->ArpBuffer
342 );
343
344 if (EFI_ERROR (Status)) {
345 return Status;
346 }
347 }
348
349 ArpPacket = (VOID *) (Private->ArpBuffer + SnpMode->MediaHeaderSize);
350
351 //
352 // for now, only handle one kind of hw and pr address
353 //
354 ArpPacket->ArpHeader = ArpHeader;
355 ArpPacket->ArpHeader.HwAddLen = (UINT8) HardwareAddrLength;
356 ArpPacket->ArpHeader.ProtAddLen = (UINT8) Private->IpLength;
357
358 //
359 // rest more generic
360 //
361 SrcProtocolAddrPtr = (UINT8 *) (&ArpPacket->SrcHardwareAddr) + HardwareAddrLength;
362 DestHardwareAddrptr = SrcProtocolAddrPtr + Private->IpLength;
363 DestProtocolAddrPtr = DestHardwareAddrptr + HardwareAddrLength;
364
365 CopyMem (DestProtocolAddrPtr, ProtocolAddrPtr, Private->IpLength);
366 CopyMem (DestHardwareAddrptr, HardwareAddrPtr, HardwareAddrLength);
367 CopyMem (SrcProtocolAddrPtr, &PxeBcMode->StationIp, Private->IpLength);
368 CopyMem (
369 &ArpPacket->SrcHardwareAddr,
370 &SnpMode->CurrentAddress,
371 HardwareAddrLength
372 );
373
374 return SendPacket (
375 Private,
376 Private->ArpBuffer,
377 ArpPacket,
378 sizeof (ARP_HEADER) + ((Private->IpLength + HardwareAddrLength) << 1),
379 &SnpMode->BroadcastAddress,
380 PXE_PROTOCOL_ETHERNET_ARP,
381 EFI_PXE_BASE_CODE_FUNCTION_ARP
382 );
383 }
384
385 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
386
387 //
388 // check for address - if not there, send ARP request, wait and check again
389 // not how it would be done in a full system
390 //
391 #define ARP_REQUEST_TIMEOUT_MS 500 // try for half a second
392
393 ////////////////////////////////////////////////////////////
394 //
395 // BC Arp Routine
396 //
397
398 /**
399
400
401 **/
402 EFI_STATUS
403 EFIAPI
404 BcArp (
405 IN EFI_PXE_BASE_CODE_PROTOCOL * This,
406 IN EFI_IP_ADDRESS * ProtocolAddrPtr,
407 OUT EFI_MAC_ADDRESS * HardwareAddrPtr OPTIONAL
408 )
409 {
410 EFI_MAC_ADDRESS Mac;
411 EFI_STATUS StatCode;
412 PXE_BASECODE_DEVICE *Private;
413
414 //
415 // Lock the instance data and make sure started
416 //
417 StatCode = EFI_SUCCESS;
418
419 if (This == NULL) {
420 DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));
421 return EFI_INVALID_PARAMETER;
422 }
423
424 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
425
426 if (Private == NULL) {
427 DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
428 return EFI_INVALID_PARAMETER;
429 }
430
431 EfiAcquireLock (&Private->Lock);
432
433 if (This->Mode == NULL || !This->Mode->Started) {
434 DEBUG ((DEBUG_ERROR, "BC was not started."));
435 EfiReleaseLock (&Private->Lock);
436 return EFI_NOT_STARTED;
437 }
438
439 DEBUG ((DEBUG_INFO, "\nBcArp()"));
440
441 //
442 // Issue BC command
443 //
444 if (ProtocolAddrPtr == NULL) {
445 DEBUG (
446 (DEBUG_INFO,
447 "\nBcArp() Exit #1 %Xh (%r)",
448 EFI_INVALID_PARAMETER,
449 EFI_INVALID_PARAMETER)
450 );
451
452 EfiReleaseLock (&Private->Lock);
453 return EFI_INVALID_PARAMETER;
454 }
455
456 if (HardwareAddrPtr == NULL) {
457 HardwareAddrPtr = &Mac;
458 }
459
460 ZeroMem (HardwareAddrPtr, Private->SimpleNetwork->Mode->HwAddressSize);
461
462 if (GetHwAddr (Private, ProtocolAddrPtr, HardwareAddrPtr)) {
463 DEBUG (
464 (DEBUG_INFO,
465 "\nBcArp() Exit #2 %Xh (%r)",
466 EFI_SUCCESS,
467 EFI_SUCCESS)
468 );
469
470 EfiReleaseLock (&Private->Lock);
471 return EFI_SUCCESS;
472 }
473
474 StatCode = DoArp (Private, ProtocolAddrPtr, HardwareAddrPtr);
475
476 DEBUG ((DEBUG_INFO, "\nBcArp() Exit #3 %Xh (%r)", StatCode, StatCode));
477
478 EfiReleaseLock (&Private->Lock);
479 return StatCode;
480 }
481
482 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
483
484 /**
485
486 @return EFI_SUCCESS := MAC address found
487 @return other := MAC address could not be found
488
489 **/
490 EFI_STATUS
491 DoArp (
492 IN PXE_BASECODE_DEVICE *Private,
493 IN EFI_IP_ADDRESS *ProtocolAddrPtr,
494 OUT EFI_MAC_ADDRESS *HardwareAddrPtr
495 )
496 {
497 EFI_STATUS StatCode;
498 EFI_EVENT TimeoutEvent;
499 UINTN HeaderSize;
500 UINTN BufferSize;
501 UINT16 Protocol;
502
503 DEBUG ((DEBUG_INFO, "\nDoArp()"));
504
505 //
506 //
507 //
508 StatCode = SendRequest (Private, ProtocolAddrPtr, HardwareAddrPtr);
509
510 if (EFI_ERROR (StatCode)) {
511 DEBUG ((DEBUG_INFO, "\nDoArp() Exit #1 %Xh (%r)", StatCode, StatCode));
512 return StatCode;
513 }
514 //
515 //
516 //
517 StatCode = gBS->CreateEvent (
518 EVT_TIMER,
519 TPL_CALLBACK,
520 NULL,
521 NULL,
522 &TimeoutEvent
523 );
524
525 if (EFI_ERROR (StatCode)) {
526 return StatCode;
527 }
528
529 StatCode = gBS->SetTimer (
530 TimeoutEvent,
531 TimerRelative,
532 ARP_REQUEST_TIMEOUT_MS * 10000
533 );
534
535 if (EFI_ERROR (StatCode)) {
536 gBS->CloseEvent (TimeoutEvent);
537 return StatCode;
538 }
539 //
540 //
541 //
542 for (;;) {
543 StatCode = WaitForReceive (
544 Private,
545 EFI_PXE_BASE_CODE_FUNCTION_ARP,
546 TimeoutEvent,
547 &HeaderSize,
548 &BufferSize,
549 &Protocol
550 );
551
552 if (EFI_ERROR (StatCode)) {
553 break;
554 }
555
556 if (Protocol != PXE_PROTOCOL_ETHERNET_ARP) {
557 continue;
558 }
559
560 HandleArpReceive (
561 Private,
562 (ARP_PACKET *) (Private->ReceiveBufferPtr + HeaderSize),
563 Private->ReceiveBufferPtr
564 );
565
566 if (GetHwAddr (Private, ProtocolAddrPtr, HardwareAddrPtr)) {
567 break;
568 }
569 }
570
571 DEBUG (
572 (DEBUG_INFO,
573 "\nDoArp() Exit #2 %Xh, (%r)",
574 StatCode,
575 StatCode)
576 );
577
578 gBS->CloseEvent (TimeoutEvent);
579
580 return StatCode;
581 }
582
583 /* eof - pxe_bc_arp.c */