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