Fix capitalization
[mirror_edk2.git] / EdkModulePkg / Universal / Network / PxeBc / Dxe / pxe_bc_arp.c
1 /*++
2
3 Copyright (c) 2006, 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 EFI_STATUS Status;
344 UINTN HardwareAddrLength;
345 UINT8 *SrcProtocolAddrPtr;
346 UINT8 *DestHardwareAddrptr;
347 UINT8 *DestProtocolAddrPtr;
348
349 //
350 //
351 //
352 PxeBcMode = Private->EfiBc.Mode;
353 SnpMode = Private->SimpleNetwork->Mode;
354 HardwareAddrLength = SnpMode->HwAddressSize;
355
356 //
357 // Allocate ARP buffer
358 //
359 if (Private->ArpBuffer == NULL) {
360 Status = gBS->AllocatePool (
361 EfiBootServicesData,
362 SnpMode->MediaHeaderSize + sizeof (ARP_PACKET),
363 (VOID **) &Private->ArpBuffer
364 );
365
366 if (EFI_ERROR (Status)) {
367 return Status;
368 }
369 }
370
371 ArpPacket = (VOID *) (Private->ArpBuffer + SnpMode->MediaHeaderSize);
372
373 //
374 // for now, only handle one kind of hw and pr address
375 //
376 ArpPacket->ArpHeader = ArpHeader;
377 ArpPacket->ArpHeader.HwAddLen = (UINT8) HardwareAddrLength;
378 ArpPacket->ArpHeader.ProtAddLen = (UINT8) Private->IpLength;
379
380 //
381 // rest more generic
382 //
383 SrcProtocolAddrPtr = (UINT8 *) (&ArpPacket->SrcHardwareAddr) + HardwareAddrLength;
384 DestHardwareAddrptr = SrcProtocolAddrPtr + Private->IpLength;
385 DestProtocolAddrPtr = DestHardwareAddrptr + HardwareAddrLength;
386
387 CopyMem (DestProtocolAddrPtr, ProtocolAddrPtr, Private->IpLength);
388 CopyMem (DestHardwareAddrptr, HardwareAddrPtr, HardwareAddrLength);
389 CopyMem (SrcProtocolAddrPtr, &PxeBcMode->StationIp, Private->IpLength);
390 CopyMem (
391 &ArpPacket->SrcHardwareAddr,
392 &SnpMode->CurrentAddress,
393 HardwareAddrLength
394 );
395
396 return SendPacket (
397 Private,
398 Private->ArpBuffer,
399 ArpPacket,
400 sizeof (ARP_HEADER) + ((Private->IpLength + HardwareAddrLength) << 1),
401 &SnpMode->BroadcastAddress,
402 PXE_PROTOCOL_ETHERNET_ARP,
403 EFI_PXE_BASE_CODE_FUNCTION_ARP
404 );
405 }
406
407 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
408
409 //
410 // check for address - if not there, send ARP request, wait and check again
411 // not how it would be done in a full system
412 //
413 #define ARP_REQUEST_TIMEOUT_MS 500 // try for half a second
414
415 ////////////////////////////////////////////////////////////
416 //
417 // BC Arp Routine
418 //
419 EFI_STATUS
420 EFIAPI
421 BcArp (
422 IN EFI_PXE_BASE_CODE_PROTOCOL * This,
423 IN EFI_IP_ADDRESS * ProtocolAddrPtr,
424 OUT EFI_MAC_ADDRESS * HardwareAddrPtr OPTIONAL
425 )
426 /*++
427 Routine description:
428 PxeBc ARP API.
429
430 Parameters:
431 This := Pointer to PxeBc interface
432 ProtocolAddrPtr := Pointer to IP address to find
433 HardwareAddrPtr := Pointer to MAC address found.
434
435 Returns:
436 --*/
437 {
438 EFI_MAC_ADDRESS Mac;
439 EFI_STATUS StatCode;
440 PXE_BASECODE_DEVICE *Private;
441
442 //
443 // Lock the instance data and make sure started
444 //
445 StatCode = EFI_SUCCESS;
446
447 if (This == NULL) {
448 DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));
449 return EFI_INVALID_PARAMETER;
450 }
451
452 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
453
454 if (Private == NULL) {
455 DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
456 return EFI_INVALID_PARAMETER;
457 }
458
459 EfiAcquireLock (&Private->Lock);
460
461 if (This->Mode == NULL || !This->Mode->Started) {
462 DEBUG ((EFI_D_ERROR, "BC was not started."));
463 EfiReleaseLock (&Private->Lock);
464 return EFI_NOT_STARTED;
465 }
466
467 DEBUG ((EFI_D_INFO, "\nBcArp()"));
468
469 //
470 // Issue BC command
471 //
472 if (ProtocolAddrPtr == NULL) {
473 DEBUG (
474 (EFI_D_INFO,
475 "\nBcArp() Exit #1 %Xh (%r)",
476 EFI_INVALID_PARAMETER,
477 EFI_INVALID_PARAMETER)
478 );
479
480 EfiReleaseLock (&Private->Lock);
481 return EFI_INVALID_PARAMETER;
482 }
483
484 if (HardwareAddrPtr == NULL) {
485 HardwareAddrPtr = &Mac;
486 }
487
488 ZeroMem (HardwareAddrPtr, Private->SimpleNetwork->Mode->HwAddressSize);
489
490 if (GetHwAddr (Private, ProtocolAddrPtr, HardwareAddrPtr)) {
491 DEBUG (
492 (EFI_D_INFO,
493 "\nBcArp() Exit #2 %Xh (%r)",
494 EFI_SUCCESS,
495 EFI_SUCCESS)
496 );
497
498 EfiReleaseLock (&Private->Lock);
499 return EFI_SUCCESS;
500 }
501
502 StatCode = DoArp (Private, ProtocolAddrPtr, HardwareAddrPtr);
503
504 DEBUG ((EFI_D_INFO, "\nBcArp() Exit #3 %Xh (%r)", StatCode, StatCode));
505
506 EfiReleaseLock (&Private->Lock);
507 return StatCode;
508 }
509
510 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
511 EFI_STATUS
512 DoArp (
513 IN PXE_BASECODE_DEVICE *Private,
514 IN EFI_IP_ADDRESS *ProtocolAddrPtr,
515 OUT EFI_MAC_ADDRESS *HardwareAddrPtr
516 )
517 /*++
518 Routine description:
519 Internal ARP implementation.
520
521 Parameters:
522 Private := Pointer to PxeBc interface
523 ProtocolAddrPtr := Pointer to IP address to find
524 HardwareAddrPtr := Pointer to MAC address found
525
526 Returns:
527 EFI_SUCCESS := MAC address found
528 other := MAC address could not be found
529 --*/
530 {
531 EFI_STATUS StatCode;
532 EFI_EVENT TimeoutEvent;
533 UINTN HeaderSize;
534 UINTN BufferSize;
535 UINT16 Protocol;
536
537 DEBUG ((EFI_D_INFO, "\nDoArp()"));
538
539 //
540 //
541 //
542 StatCode = SendRequest (Private, ProtocolAddrPtr, HardwareAddrPtr);
543
544 if (EFI_ERROR (StatCode)) {
545 DEBUG ((EFI_D_INFO, "\nDoArp() Exit #1 %Xh (%r)", StatCode, StatCode));
546 return StatCode;
547 }
548 //
549 //
550 //
551 StatCode = gBS->CreateEvent (
552 EFI_EVENT_TIMER,
553 EFI_TPL_CALLBACK,
554 NULL,
555 NULL,
556 &TimeoutEvent
557 );
558
559 if (EFI_ERROR (StatCode)) {
560 return StatCode;
561 }
562
563 StatCode = gBS->SetTimer (
564 TimeoutEvent,
565 TimerRelative,
566 ARP_REQUEST_TIMEOUT_MS * 10000
567 );
568
569 if (EFI_ERROR (StatCode)) {
570 gBS->CloseEvent (TimeoutEvent);
571 return StatCode;
572 }
573 //
574 //
575 //
576 for (;;) {
577 StatCode = WaitForReceive (
578 Private,
579 EFI_PXE_BASE_CODE_FUNCTION_ARP,
580 TimeoutEvent,
581 &HeaderSize,
582 &BufferSize,
583 &Protocol
584 );
585
586 if (EFI_ERROR (StatCode)) {
587 break;
588 }
589
590 if (Protocol != PXE_PROTOCOL_ETHERNET_ARP) {
591 continue;
592 }
593
594 HandleArpReceive (
595 Private,
596 (ARP_PACKET *) (Private->ReceiveBufferPtr + HeaderSize),
597 Private->ReceiveBufferPtr
598 );
599
600 if (GetHwAddr (Private, ProtocolAddrPtr, HardwareAddrPtr)) {
601 break;
602 }
603 }
604
605 DEBUG (
606 (EFI_D_INFO,
607 "\nDoArp() Exit #2 %Xh, (%r)",
608 StatCode,
609 StatCode)
610 );
611
612 gBS->CloseEvent (TimeoutEvent);
613
614 return StatCode;
615 }
616
617 /* eof - pxe_bc_arp.c */