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