]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/PxeBcDxe/Pxe_bc_ip.c
Patch to remove STATIC modifier. This is on longer recommended by EFI Framework codin...
[mirror_edk2.git] / MdeModulePkg / Universal / Network / PxeBcDxe / Pxe_bc_ip.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_ip.c\r
14\r
15Abstract:\r
16\r
17\r
18**/\r
19\r
20#include "Bc.h"\r
21\r
22/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
23\r
24/**\r
25 Check if two IP addresses are on the same subnet.\r
26\r
27 @param IpLength Length of IP address in bytes.\r
28 @param Ip1 IP address to check.\r
29 @param Ip2 IP address to check.\r
30 @param SubnetMask Subnet mask to check with.\r
31\r
32 @retval TRUE IP addresses are on the same subnet.\r
33 @retval FALSE IP addresses are on different subnets.\r
34\r
35**/\r
36BOOLEAN\r
37OnSameSubnet (\r
38 IN UINTN IpLength,\r
39 IN EFI_IP_ADDRESS *Ip1,\r
40 IN EFI_IP_ADDRESS *Ip2,\r
41 IN EFI_IP_ADDRESS *SubnetMask\r
42 )\r
43{\r
44 if (IpLength == 0 || Ip1 == NULL || Ip2 == NULL || SubnetMask == NULL) {\r
45 return FALSE;\r
46 }\r
47\r
48 while (IpLength-- != 0) {\r
49 if ((Ip1->v6.Addr[IpLength] ^ Ip2->v6.Addr[IpLength]) & SubnetMask->v6.Addr[IpLength]) {\r
50 return FALSE;\r
51 }\r
52 }\r
53\r
54 return TRUE;\r
55}\r
56\r
57/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
58\r
59/**\r
60 Add router to router table.\r
61\r
62 @param Private Pointer PxeBc instance data.\r
63 @param RouterIpPtr Pointer to router IP address.\r
64\r
65 @return Nothing\r
66\r
67**/\r
68VOID\r
69IpAddRouter (\r
70 IN PXE_BASECODE_DEVICE *Private,\r
71 IN EFI_IP_ADDRESS *RouterIpPtr\r
72 )\r
73{\r
74 EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
75 UINTN Index;\r
76\r
77 if (Private == NULL || RouterIpPtr == NULL) {\r
78 return ;\r
79 }\r
80\r
81 PxeBcMode = Private->EfiBc.Mode;\r
82\r
83 //\r
84 // if we are filled up or this is not on the same subnet, forget it\r
85 //\r
86 if ((PxeBcMode->RouteTableEntries == PXE_ROUTER_TABLE_SIZE) ||\r
87 !OnSameSubnet(Private->IpLength, &PxeBcMode->StationIp, RouterIpPtr, &PxeBcMode->SubnetMask)) {\r
88 return ;\r
89 }\r
90 //\r
91 // make sure we don't already have it\r
92 //\r
93 for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {\r
94 if (!CompareMem (\r
95 &PxeBcMode->RouteTable[Index].GwAddr,\r
96 RouterIpPtr,\r
97 Private->IpLength\r
98 )) {\r
99 return ;\r
100 }\r
101 }\r
102 //\r
103 // keep it\r
104 //\r
105 ZeroMem (\r
106 &PxeBcMode->RouteTable[PxeBcMode->RouteTableEntries],\r
107 sizeof (EFI_PXE_BASE_CODE_ROUTE_ENTRY)\r
108 );\r
109\r
110 CopyMem (\r
111 &PxeBcMode->RouteTable[PxeBcMode->RouteTableEntries++].GwAddr,\r
112 RouterIpPtr,\r
113 Private->IpLength\r
114 );\r
115}\r
116\r
117/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
118\r
119//\r
120// return router ip to use for DestIp (0 if none)\r
121//\r
772db4bb 122EFI_IP_ADDRESS *\r
123GetRouterIp (\r
124 PXE_BASECODE_DEVICE *Private,\r
125 EFI_IP_ADDRESS *DestIpPtr\r
126 )\r
127{\r
128 EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
129 UINTN Index;\r
130\r
131 if (Private == NULL || DestIpPtr == NULL) {\r
132 return NULL;\r
133 }\r
134\r
135 PxeBcMode = Private->EfiBc.Mode;\r
136\r
137 for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {\r
138 if (OnSameSubnet (\r
139 Private->IpLength,\r
140 &PxeBcMode->RouteTable[Index].IpAddr,\r
141 DestIpPtr,\r
142 &PxeBcMode->RouteTable[Index].SubnetMask\r
143 )) {\r
144 return &PxeBcMode->RouteTable[Index].GwAddr;\r
145 }\r
146 }\r
147\r
148 return NULL;\r
149}\r
150\r
151/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
152\r
153//\r
154// routine to send ipv4 packet\r
155// ipv4 header of length HdrLth in TransmitBufferPtr\r
156// routine fills in ipv4hdr Ver_Hdl, TotalLength, and Checksum, moves in Data\r
157// and gets dest MAC address\r
158//\r
159#define IP_TX_BUFFER ((IPV4_BUFFER *) Private->TransmitBufferPtr)\r
160#define IP_TX_HEADER IP_TX_BUFFER->IpHeader\r
161\r
162EFI_STATUS\r
163Ipv4Xmt (\r
164 PXE_BASECODE_DEVICE *Private,\r
165 UINT32 GatewayIp,\r
166 UINTN IpHeaderLength,\r
167 UINTN TotalHeaderLength,\r
168 VOID *Data,\r
169 UINTN DataLength,\r
170 EFI_PXE_BASE_CODE_FUNCTION Function\r
171 )\r
172{\r
173 EFI_MAC_ADDRESS DestMac;\r
174 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
175 EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
176 EFI_STATUS StatCode;\r
177 UINTN PacketLength;\r
178\r
179 Snp = Private->SimpleNetwork;\r
180 PxeBcMode = Private->EfiBc.Mode;\r
181 StatCode = EFI_SUCCESS;\r
182 PacketLength = TotalHeaderLength + DataLength;\r
183\r
184 //\r
185 // get dest MAC address\r
186 // multicast - convert to hw equiv\r
187 // unicast on same net, use arp\r
188 // on different net, arp for router\r
189 //\r
190 if (IP_TX_HEADER.DestAddr.L == BROADCAST_IPv4) {\r
191 CopyMem (&DestMac, &Snp->Mode->BroadcastAddress, sizeof (DestMac));\r
192 } else if (IS_MULTICAST (&IP_TX_HEADER.DestAddr)) {\r
193 StatCode = (*Snp->MCastIpToMac) (Snp, PxeBcMode->UsingIpv6, (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr, &DestMac);\r
194 } else {\r
195 UINT32 Ip;\r
196\r
197 if (OnSameSubnet (\r
198 Private->IpLength,\r
199 &PxeBcMode->StationIp,\r
200 (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr,\r
201 &PxeBcMode->SubnetMask\r
202 )) {\r
203 Ip = IP_TX_HEADER.DestAddr.L;\r
204 } else if (GatewayIp != 0) {\r
205 Ip = GatewayIp;\r
206 } else {\r
207 EFI_IP_ADDRESS *TmpIp;\r
208\r
209 TmpIp = GetRouterIp (Private, (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr);\r
210\r
211 if (TmpIp == NULL) {\r
212 DEBUG (\r
213 (DEBUG_WARN,\r
214 "\nIpv4Xmit() Exit #1 %xh (%r)",\r
215 EFI_NO_RESPONSE,\r
216 EFI_NO_RESPONSE)\r
217 );\r
218\r
219 return EFI_NO_RESPONSE;\r
220 //\r
221 // no router\r
222 //\r
223 }\r
224\r
225 Ip = TmpIp->Addr[0];\r
226 }\r
227\r
228 if (!GetHwAddr (\r
229 Private,\r
230 (EFI_IP_ADDRESS *) &Ip,\r
231 (EFI_MAC_ADDRESS *) &DestMac\r
232 )) {\r
233 if (!PxeBcMode->AutoArp) {\r
234 DEBUG (\r
235 (DEBUG_WARN,\r
236 "\nIpv4Xmit() Exit #2 %xh (%r)",\r
237 EFI_DEVICE_ERROR,\r
238 EFI_DEVICE_ERROR)\r
239 );\r
240\r
241 return EFI_DEVICE_ERROR;\r
242 } else {\r
243 StatCode = DoArp (\r
244 Private,\r
245 (EFI_IP_ADDRESS *) &Ip,\r
246 (EFI_MAC_ADDRESS *) &DestMac\r
247 );\r
248 }\r
249 }\r
250 }\r
251\r
252 if (EFI_ERROR (StatCode)) {\r
253 DEBUG ((DEBUG_WARN, "\nIpv4Xmit() Exit #3 %xh (%r)", StatCode, StatCode));\r
254 return StatCode;\r
255 }\r
256 //\r
257 // fill in packet info\r
258 //\r
259 SET_IPV4_VER_HDL (&IP_TX_HEADER, IpHeaderLength);\r
260 IP_TX_HEADER.TotalLength = HTONS (PacketLength);\r
261 IP_TX_HEADER.HeaderChecksum = IpChecksum ((UINT16 *) &IP_TX_HEADER, IpHeaderLength);\r
262 CopyMem (((UINT8 *) &IP_TX_HEADER) + TotalHeaderLength, Data, DataLength);\r
263\r
264 //\r
265 // send it\r
266 //\r
267 return SendPacket (\r
268 Private,\r
269 (UINT8 *) &IP_TX_HEADER - Snp->Mode->MediaHeaderSize,\r
270 &IP_TX_HEADER,\r
271 PacketLength,\r
272 &DestMac,\r
273 PXE_PROTOCOL_ETHERNET_IP,\r
274 Function\r
275 );\r
276}\r
277\r
278/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
279\r
280//\r
281// send ipv4 packet with option\r
282//\r
283EFI_STATUS\r
284Ipv4SendWOp (\r
285 PXE_BASECODE_DEVICE *Private,\r
286 UINT32 GatewayIp,\r
287 UINT8 *Msg,\r
288 UINTN MessageLength,\r
289 UINT8 Prot,\r
290 UINT8 *Option,\r
291 UINTN OptionLength,\r
292 UINT32 DestIp,\r
293 EFI_PXE_BASE_CODE_FUNCTION Function\r
294 )\r
295{\r
296 EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
297 UINTN HdrLth;\r
298\r
299 PxeBcMode = Private->EfiBc.Mode;\r
300 HdrLth = sizeof (IPV4_HEADER) + OptionLength;\r
301\r
302 ZeroMem ((VOID *) &IP_TX_HEADER, sizeof (IPV4_HEADER));\r
303 IP_TX_HEADER.TimeToLive = PxeBcMode->TTL;\r
304 IP_TX_HEADER.TypeOfService = PxeBcMode->ToS;\r
305 IP_TX_HEADER.Protocol = Prot;\r
306 IP_TX_HEADER.SrcAddr.L = *(UINT32 *) &PxeBcMode->StationIp;\r
307 IP_TX_HEADER.DestAddr.L = DestIp;\r
308 IP_TX_HEADER.Id = Random (Private);\r
309 CopyMem (IP_TX_BUFFER->u.Data, Option, OptionLength);\r
310 return Ipv4Xmt (\r
311 Private,\r
312 GatewayIp,\r
313 HdrLth,\r
314 HdrLth,\r
315 Msg,\r
316 MessageLength,\r
317 Function\r
318 );\r
319}\r
320\r
321/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
322\r
323//\r
324// send MessageLength message at MessagePtr - higher level protocol header already in TransmitBufferPtr, length HdrSize\r
325//\r
326EFI_STATUS\r
327Ip4Send (\r
328 PXE_BASECODE_DEVICE *Private, // pointer to instance data\r
329 UINTN MayFrag, //\r
330 UINT8 Prot, // protocol\r
331 UINT32 SrcIp, // Source IP address\r
332 UINT32 DestIp, // Destination IP address\r
333 UINT32 GatewayIp, // used if not NULL and needed\r
334 UINTN HdrSize, // protocol header byte length\r
335 UINT8 *MessagePtr, // pointer to data\r
336 UINTN MessageLength // data byte length\r
337 )\r
338{\r
339 EFI_STATUS StatCode;\r
340 UINTN TotDataLength;\r
341\r
342 TotDataLength = HdrSize + MessageLength;\r
343\r
344 if (TotDataLength > MAX_IPV4_DATA_SIZE) {\r
345 DEBUG (\r
346 (DEBUG_WARN,\r
347 "\nIp4Send() Exit #1 %xh (%r)",\r
348 EFI_BAD_BUFFER_SIZE,\r
349 EFI_BAD_BUFFER_SIZE)\r
350 );\r
351\r
352 return EFI_BAD_BUFFER_SIZE;\r
353 }\r
354\r
355 ZeroMem ((VOID *) &IP_TX_HEADER, sizeof (IPV4_HEADER));\r
356 IP_TX_HEADER.TimeToLive = DEFAULT_TTL;\r
357 IP_TX_HEADER.Protocol = Prot;\r
358 IP_TX_HEADER.SrcAddr.L = SrcIp;\r
359 IP_TX_HEADER.DestAddr.L = DestIp;\r
360 IP_TX_HEADER.Id = Random (Private);\r
361\r
362 if (!MayFrag) {\r
363 *(UINT8 *) (&IP_TX_HEADER.FragmentFields) = IP_NO_FRAG >> 8;\r
364 }\r
365 //\r
366 // check for need to fragment\r
367 //\r
368 if (TotDataLength > MAX_IPV4_FRAME_DATA_SIZE) {\r
369 UINTN DataLengthSent;\r
370 UINT16 FragmentOffset;\r
371\r
372 FragmentOffset = IP_MORE_FRAG;\r
373 //\r
374 // frag offset field\r
375 //\r
376 if (!MayFrag) {\r
377 DEBUG (\r
378 (DEBUG_WARN,\r
379 "\nIp4Send() Exit #2 %xh (%r)",\r
380 EFI_BAD_BUFFER_SIZE,\r
381 EFI_BAD_BUFFER_SIZE)\r
382 );\r
383\r
384 return EFI_BAD_BUFFER_SIZE;\r
385 }\r
386 //\r
387 // send out in fragments - first includes upper level header\r
388 // all are max and include more frag bit except last\r
389 //\r
390 * (UINT8 *) (&IP_TX_HEADER.FragmentFields) = IP_MORE_FRAG >> 8;\r
391\r
392#define IPV4_FRAG_SIZE (MAX_IPV4_FRAME_DATA_SIZE & 0xfff8)\r
393#define IPV4_FRAG_OFF_INC (IPV4_FRAG_SIZE >> 3)\r
394\r
395 DataLengthSent = IPV4_FRAG_SIZE - HdrSize;\r
396\r
397 StatCode = Ipv4Xmt (\r
398 Private,\r
399 GatewayIp,\r
400 sizeof (IPV4_HEADER),\r
401 sizeof (IPV4_HEADER) + HdrSize,\r
402 MessagePtr,\r
403 DataLengthSent,\r
404 Private->Function\r
405 );\r
406\r
407 if (EFI_ERROR (StatCode)) {\r
408 DEBUG (\r
409 (DEBUG_WARN,\r
410 "\nIp4Send() Exit #3 %xh (%r)",\r
411 StatCode,\r
412 StatCode)\r
413 );\r
414\r
415 return StatCode;\r
416 }\r
417\r
418 MessagePtr += DataLengthSent;\r
419 MessageLength -= DataLengthSent;\r
420 FragmentOffset += IPV4_FRAG_OFF_INC;\r
421 IP_TX_HEADER.FragmentFields = HTONS (FragmentOffset);\r
422\r
423 while (MessageLength > IPV4_FRAG_SIZE) {\r
424 StatCode = Ipv4Xmt (\r
425 Private,\r
426 GatewayIp,\r
427 sizeof (IPV4_HEADER),\r
428 sizeof (IPV4_HEADER),\r
429 MessagePtr,\r
430 IPV4_FRAG_SIZE,\r
431 Private->Function\r
432 );\r
433\r
434 if (EFI_ERROR (StatCode)) {\r
435 DEBUG (\r
436 (DEBUG_WARN,\r
437 "\nIp4Send() Exit #3 %xh (%r)",\r
438 StatCode,\r
439 StatCode)\r
440 );\r
441\r
442 return StatCode;\r
443 }\r
444\r
445 MessagePtr += IPV4_FRAG_SIZE;\r
446 MessageLength -= IPV4_FRAG_SIZE;\r
447 FragmentOffset += IPV4_FRAG_OFF_INC;\r
448 IP_TX_HEADER.FragmentFields = HTONS (FragmentOffset);\r
449 }\r
450\r
451 * (UINT8 *) (&IP_TX_HEADER.FragmentFields) &= ~(IP_MORE_FRAG >> 8);\r
452 HdrSize = 0;\r
453 }\r
454 //\r
455 // transmit\r
456 //\r
457 return Ipv4Xmt (\r
458 Private,\r
459 GatewayIp,\r
460 sizeof (IPV4_HEADER),\r
461 sizeof (IPV4_HEADER) + HdrSize,\r
462 MessagePtr,\r
463 MessageLength,\r
464 Private->Function\r
465 );\r
466}\r
467\r
468/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
469\r
470//\r
471// return true if dst IP in receive header matched with what's enabled\r
472//\r
772db4bb 473BOOLEAN\r
474IPgood (\r
475 PXE_BASECODE_DEVICE *Private,\r
476 IPV4_HEADER *IpHeader\r
477 )\r
478{\r
479 EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
480 UINTN Index;\r
481\r
482 PxeBcMode = Private->EfiBc.Mode;\r
483\r
484 if (PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) {\r
485 return TRUE;\r
486 }\r
487\r
488 if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) &&\r
489 IS_MULTICAST (&IpHeader->DestAddr)\r
490 ) {\r
491 return TRUE;\r
492 }\r
493\r
494 if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) &&\r
495 PxeBcMode->StationIp.Addr[0] == IpHeader->DestAddr.L\r
496 ) {\r
497 return TRUE;\r
498 }\r
499\r
500 if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) && IpHeader->DestAddr.L == BROADCAST_IPv4) {\r
501 return TRUE;\r
502 }\r
503\r
504 for (Index = 0; Index < PxeBcMode->IpFilter.IpCnt; ++Index) {\r
505 if (IpHeader->DestAddr.L == PxeBcMode->IpFilter.IpList[Index].Addr[0]) {\r
506 return TRUE;\r
507 }\r
508 }\r
509\r
510 return FALSE;\r
511}\r
512\r
513/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
514\r
515//\r
516// receive up to MessageLength message into MessagePtr for protocol Prot\r
517// return message length, src/dest ips if select any, and pointer to protocol\r
518// header routine will filter based on source and/or dest ip if OpFlags set.\r
519//\r
520EFI_STATUS\r
521IpReceive (\r
522 PXE_BASECODE_DEVICE *Private,\r
523 PXE_OPFLAGS OpFlags,\r
524 EFI_IP_ADDRESS *SrcIpPtr,\r
525 EFI_IP_ADDRESS *DestIpPtr,\r
526 UINT8 Prot,\r
527 VOID *HeaderPtr,\r
528 UINTN HdrSize,\r
529 UINT8 *MessagePtr,\r
530 UINTN *MessageLengthPtr,\r
531 EFI_EVENT TimeoutEvent\r
532 )\r
533{\r
534 EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
535 EFI_STATUS StatCode;\r
536 UINTN ByteCount;\r
537 UINTN FragmentCount;\r
538 UINTN ExpectedPacketLength;\r
539 UINTN Id;\r
540 BOOLEAN GotFirstFragment;\r
541 BOOLEAN GotLastFragment;\r
542\r
543 DEBUG (\r
544 (DEBUG_NET,\r
545 "\nIpReceive() Hdr=%Xh HdrSz=%d Data=%Xh DataSz=%d",\r
546 HeaderPtr,\r
547 HdrSize,\r
548 MessagePtr,\r
549 *MessageLengthPtr)\r
550 );\r
551\r
552 PxeBcMode = Private->EfiBc.Mode;\r
553 PxeBcMode->IcmpErrorReceived = FALSE;\r
554\r
555 ExpectedPacketLength = 0;\r
556 GotFirstFragment = FALSE;\r
557 GotLastFragment = FALSE;\r
558 FragmentCount = 0;\r
559 ByteCount = 0;\r
560 Id = 0;\r
561\r
562 for (;;) {\r
563 IPV4_HEADER IpHdr;\r
564 UINTN FFlds;\r
565 UINTN TotalLength;\r
566 UINTN FragmentOffset;\r
567 UINTN HeaderSize;\r
568 UINTN BufferSize;\r
569 UINTN IpHeaderLength;\r
570 UINTN DataLength;\r
571 UINT16 Protocol;\r
572 UINT8 *NextHdrPtr;\r
573 UINT8 *PacketPtr;\r
574\r
575 StatCode = WaitForReceive (\r
576 Private,\r
577 Private->Function,\r
578 TimeoutEvent,\r
579 &HeaderSize,\r
580 &BufferSize,\r
581 &Protocol\r
582 );\r
583\r
584 if (EFI_ERROR (StatCode)) {\r
585 return StatCode;\r
586 }\r
587\r
588 PacketPtr = Private->ReceiveBufferPtr + HeaderSize;\r
589\r
590 if (Protocol == PXE_PROTOCOL_ETHERNET_ARP) {\r
591 HandleArpReceive (\r
592 Private,\r
593 (ARP_PACKET *) PacketPtr,\r
594 Private->ReceiveBufferPtr\r
595 );\r
596\r
597 continue;\r
598 }\r
599\r
600 if (Protocol != PXE_PROTOCOL_ETHERNET_IP) {\r
601 continue;\r
602 }\r
603\r
604#define IpRxHeader ((IPV4_HEADER *) PacketPtr)\r
605\r
606 //\r
607 // filter for version & check sum\r
608 //\r
609 IpHeaderLength = IPV4_HEADER_LENGTH (IpRxHeader);\r
610\r
611 if ((IpRxHeader->VersionIhl >> 4) != IPVER4) {\r
612 continue;\r
613 }\r
614\r
615 if (IpChecksum ((UINT16 *) IpRxHeader, IpHeaderLength)) {\r
616 continue;\r
617 }\r
618\r
619 CopyMem (&IpHdr, IpRxHeader, sizeof (IpHdr));\r
620 TotalLength = NTOHS (IpHdr.TotalLength);\r
621\r
622 if (IpHdr.Protocol == PROT_TCP) {\r
623 //\r
624 // The NextHdrPtr is used to seed the header buffer we are passing back.\r
625 // That being the case, we want to see everything in pPkt which contains\r
626 // everything but the ethernet (or whatever) frame. IP + TCP in this case.\r
627 //\r
628 DataLength = TotalLength;\r
629 NextHdrPtr = PacketPtr;\r
630 } else {\r
631 DataLength = TotalLength - IpHeaderLength;\r
632 NextHdrPtr = PacketPtr + IpHeaderLength;\r
633 }\r
634 //\r
635 // If this is an ICMP, it might not be for us.\r
636 // Double check the state of the IP stack and the\r
637 // packet fields before assuming it is an ICMP\r
638 // error. ICMP requests are not supported by the\r
639 // PxeBc IP stack and should be ignored.\r
640 //\r
641 if (IpHdr.Protocol == PROT_ICMP) {\r
642 ICMPV4_HEADER *Icmpv4;\r
643\r
644 Icmpv4 = (ICMPV4_HEADER *) NextHdrPtr;\r
645\r
646 //\r
647 // For now only obvious ICMP error replies will be accepted by\r
648 // this stack. This still makes us vulnerable to DoS attacks.\r
649 // But at least we will not be killed by DHCP daemons.\r
650 //\r
651 switch (Icmpv4->Type) {\r
652 case ICMP_REDIRECT:\r
653 case ICMP_ECHO:\r
654 case ICMP_ROUTER_ADV:\r
655 case ICMP_ROUTER_SOLICIT:\r
656 case ICMP_TIMESTAMP:\r
657 case ICMP_TIMESTAMP_REPLY:\r
658 case ICMP_INFO_REQ:\r
659 case ICMP_INFO_REQ_REPLY:\r
660 case ICMP_SUBNET_MASK_REQ:\r
661 case ICMP_SUBNET_MASK_REPLY:\r
662 default:\r
663 continue;\r
664\r
665 //\r
666 // %%TBD - This should be implemented.\r
667 //\r
668 case ICMP_ECHO_REPLY:\r
669 continue;\r
670\r
671 case ICMP_DEST_UNREACHABLE:\r
672 case ICMP_TIME_EXCEEDED:\r
673 case ICMP_PARAMETER_PROBLEM:\r
674 case ICMP_SOURCE_QUENCH:\r
675 PxeBcMode->IcmpErrorReceived = TRUE;\r
676\r
677 CopyMem (\r
678 &PxeBcMode->IcmpError,\r
679 NextHdrPtr,\r
680 sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)\r
681 );\r
682\r
683 DEBUG (\r
684 (DEBUG_NET,\r
685 "\nIpReceive() Exit #1 %Xh (%r)",\r
686 EFI_ICMP_ERROR,\r
687 EFI_ICMP_ERROR)\r
688 );\r
689 }\r
690\r
691 return EFI_ICMP_ERROR;\r
692 }\r
693\r
694 if (IpHdr.Protocol == PROT_IGMP) {\r
695 HandleIgmp (Private, (IGMPV2_MESSAGE *) NextHdrPtr, DataLength);\r
696\r
697 DEBUG ((DEBUG_NET, "\n IGMP"));\r
698 continue;\r
699 }\r
700 //\r
701 // check for protocol\r
702 //\r
703 if (IpHdr.Protocol != Prot) {\r
704 continue;\r
705 }\r
706 //\r
707 // do filtering\r
708 //\r
709 if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) && SrcIpPtr && SrcIpPtr->Addr[0] != IpHdr.SrcAddr.L) {\r
710 DEBUG ((DEBUG_NET, "\n Not expected source IP address."));\r
711 continue;\r
712 }\r
713\r
714 if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER) {\r
715 if (!IPgood (Private, &IpHdr)) {\r
716 continue;\r
717 }\r
718 } else if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP)) {\r
719 if (DestIpPtr == NULL) {\r
720 if (PxeBcMode->StationIp.Addr[0] != IpHdr.DestAddr.L) {\r
721 continue;\r
722 }\r
723 } else if (DestIpPtr->Addr[0] != IpHdr.DestAddr.L) {\r
724 continue;\r
725 }\r
726 }\r
727 //\r
728 // get some data we need\r
729 //\r
730 FFlds = NTOHS (IpHdr.FragmentFields);\r
731 FragmentOffset = ((FFlds & IP_FRAG_OFF_MSK) << 3);\r
732\r
733 /* Keep count of fragments that belong to this session.\r
734 * If we get packets with a different IP ID number,\r
735 * ignore them. Ignored packets should be handled\r
736 * by the upper level protocol.\r
737 */\r
738 if (FragmentCount == 0) {\r
739 Id = IpHdr.Id;\r
740\r
741 if (DestIpPtr != NULL) {\r
742 DestIpPtr->Addr[0] = IpHdr.DestAddr.L;\r
743 }\r
744\r
745 if (SrcIpPtr != NULL) {\r
746 SrcIpPtr->Addr[0] = IpHdr.SrcAddr.L;\r
747 }\r
748 } else {\r
749 if (IpHdr.Id != Id) {\r
750 continue;\r
751 }\r
752 }\r
753\r
754 ++FragmentCount;\r
755\r
756 /* Fragment management.\r
757 */\r
758 if (FragmentOffset == 0) {\r
759 /* This is the first fragment (may also be the\r
760 * only fragment).\r
761 */\r
762 GotFirstFragment = TRUE;\r
763\r
764 /* If there is a separate protocol header buffer,\r
765 * copy the header, adjust the data pointer and\r
766 * the data length.\r
767 */\r
768 if (HdrSize != 0) {\r
769 CopyMem (HeaderPtr, NextHdrPtr, HdrSize);\r
770\r
771 NextHdrPtr += HdrSize;\r
772 DataLength -= HdrSize;\r
773 }\r
774 } else {\r
775 /* If there is a separate protocol header buffer,\r
776 * adjust the fragment offset.\r
777 */\r
778 FragmentOffset -= HdrSize;\r
779 }\r
780\r
781 /* See if this is the last fragment.\r
782 */\r
783 if (!(FFlds & IP_MORE_FRAG)) {\r
784 //\r
785 // This is the last fragment (may also be the only fragment).\r
786 //\r
787 GotLastFragment = TRUE;\r
788\r
789 /* Compute the expected length of the assembled\r
790 * packet. This will be used to decide if we\r
791 * have gotten all of the fragments.\r
792 */\r
793 ExpectedPacketLength = FragmentOffset + DataLength;\r
794 }\r
795\r
796 DEBUG (\r
797 (DEBUG_NET,\r
798 "\n ID = %Xh Off = %d Len = %d",\r
799 Id,\r
800 FragmentOffset,\r
801 DataLength)\r
802 );\r
803\r
804 /* Check for receive buffer overflow.\r
805 */\r
806 if (FragmentOffset + DataLength > *MessageLengthPtr) {\r
807 /* There is not enough space in the receive\r
808 * buffer for the fragment.\r
809 */\r
810 DEBUG (\r
811 (DEBUG_NET,\r
812 "\nIpReceive() Exit #3 %Xh (%r)",\r
813 EFI_BUFFER_TOO_SMALL,\r
814 EFI_BUFFER_TOO_SMALL)\r
815 );\r
816\r
817 return EFI_BUFFER_TOO_SMALL;\r
818 }\r
819\r
820 /* Copy data into receive buffer.\r
821 */\r
822 if (DataLength != 0) {\r
823 DEBUG ((DEBUG_NET, " To = %Xh", MessagePtr + FragmentOffset));\r
824\r
825 CopyMem (MessagePtr + FragmentOffset, NextHdrPtr, DataLength);\r
826 ByteCount += DataLength;\r
827 }\r
828\r
829 /* If we have seen the first and last fragments and\r
830 * the receive byte count is at least as large as the\r
831 * expected byte count, return SUCCESS.\r
832 *\r
833 * We could be tricked by receiving a fragment twice\r
834 * but the upper level protocol should figure this\r
835 * out.\r
836 */\r
837 if (GotFirstFragment && GotLastFragment && ByteCount >= ExpectedPacketLength) {\r
838 *MessageLengthPtr = ExpectedPacketLength;\r
839 return EFI_SUCCESS;\r
840 }\r
841 }\r
842}\r
843\r
844/* eof - pxe_bc_ip.c */\r