EDK2 doxygen online documents - Firmware Encoding Index 1
EDK2 doxygen online documents - Firmware Encoding Index

MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Output.c

Go to the documentation of this file.
00001 
00015 #include "Ip4Impl.h"
00016 
00017 UINT16  mIp4Id;
00018 
00019 
00038 EFI_STATUS
00039 Ip4PrependHead (
00040   IN OUT NET_BUF                *Packet,
00041   IN     IP4_HEAD               *Head,
00042   IN     UINT8                  *Option,
00043   IN     UINT32                 OptLen
00044   )
00045 {
00046   UINT32                    HeadLen;
00047   UINT32                    Len;
00048   IP4_HEAD                  *PacketHead;
00049   BOOLEAN                   FirstFragment;
00050 
00051   //
00052   // Prepend the options: first get the option length, then copy it over.
00053   //
00054   HeadLen       = 0;
00055   FirstFragment = IP4_FIRST_FRAGMENT (Head->Fragment);
00056 
00057   Ip4CopyOption (Option, OptLen, FirstFragment, NULL, &Len);
00058 
00059   HeadLen = IP4_MIN_HEADLEN + Len;
00060   ASSERT (((Len % 4) == 0) && (HeadLen <= IP4_MAX_HEADLEN));
00061 
00062   PacketHead = (IP4_HEAD *) NetbufAllocSpace (Packet, HeadLen, NET_BUF_HEAD);
00063 
00064   if (PacketHead == NULL) {
00065     return EFI_BAD_BUFFER_SIZE;
00066   }
00067 
00068   Ip4CopyOption (Option, OptLen, FirstFragment, (UINT8 *) (PacketHead + 1), &Len);
00069 
00070   //
00071   // Set the head up, convert the host byte order to network byte order
00072   //
00073   PacketHead->Ver       = 4;
00074   PacketHead->HeadLen   = (UINT8) (HeadLen >> 2);
00075   PacketHead->Tos       = Head->Tos;
00076   PacketHead->TotalLen  = HTONS ((UINT16) Packet->TotalSize);
00077   PacketHead->Id        = HTONS (Head->Id);
00078   PacketHead->Fragment  = HTONS (Head->Fragment);
00079   PacketHead->Checksum  = 0;
00080   PacketHead->Ttl       = Head->Ttl;
00081   PacketHead->Protocol  = Head->Protocol;
00082   PacketHead->Src       = HTONL (Head->Src);
00083   PacketHead->Dst       = HTONL (Head->Dst);
00084   PacketHead->Checksum  = (UINT16) (~NetblockChecksum ((UINT8 *) PacketHead, HeadLen));
00085 
00086   Packet->Ip.Ip4        = PacketHead;
00087   return EFI_SUCCESS;
00088 }
00089 
00090 
00104 IP4_INTERFACE *
00105 Ip4SelectInterface (
00106   IN IP4_SERVICE            *IpSb,
00107   IN IP4_ADDR               Dst,
00108   IN IP4_ADDR               Src
00109   )
00110 {
00111   IP4_INTERFACE             *IpIf;
00112   IP4_INTERFACE             *Selected;
00113   LIST_ENTRY                *Entry;
00114 
00115   //
00116   // Select the interface the Dst is on if one of the connected
00117   // network. Some IP instance may be configured with 0.0.0.0/0,
00118   // don't select that interface now.
00119   //
00120   IpIf = Ip4FindNet (IpSb, Dst);
00121 
00122   if ((IpIf != NULL) && (IpIf->Ip != IP4_ALLZERO_ADDRESS)) {
00123     return IpIf;
00124   }
00125 
00126   //
00127   // If source is one of the interface address, select it.
00128   //
00129   IpIf = Ip4FindInterface (IpSb, Src);
00130 
00131   if ((IpIf != NULL) && (IpIf->Ip != IP4_ALLZERO_ADDRESS)) {
00132     return IpIf;
00133   }
00134 
00135   //
00136   // Select a configured interface as the fall back. Always prefer
00137   // an interface with non-zero address.
00138   //
00139   Selected = NULL;
00140 
00141   NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
00142     IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);
00143 
00144     if (IpIf->Configured && ((Selected == NULL) || (Selected->Ip == 0))) {
00145       Selected = IpIf;
00146     }
00147   }
00148 
00149   return Selected;
00150 }
00151 
00152 
00166 VOID
00167 Ip4SysPacketSent (
00168   IP4_PROTOCOL              *Ip4Instance,
00169   NET_BUF                   *Packet,
00170   EFI_STATUS                IoStatus,
00171   UINT32                    LinkFlag,
00172   VOID                      *Context
00173   )
00174 {
00175   NetbufFree (Packet);
00176 }
00177 
00178 
00210 EFI_STATUS
00211 Ip4Output (
00212   IN IP4_SERVICE            *IpSb,
00213   IN IP4_PROTOCOL           *IpInstance  OPTIONAL,
00214   IN NET_BUF                *Packet,
00215   IN IP4_HEAD               *Head,
00216   IN UINT8                  *Option,
00217   IN UINT32                 OptLen,
00218   IN IP4_ADDR               GateWay,
00219   IN IP4_FRAME_CALLBACK     Callback,
00220   IN VOID                   *Context
00221   )
00222 {
00223   IP4_INTERFACE             *IpIf;
00224   IP4_ROUTE_CACHE_ENTRY     *CacheEntry;
00225   IP4_ADDR                  Dest;
00226   EFI_STATUS                Status;
00227   NET_BUF                   *Fragment;
00228   UINT32                    Index;
00229   UINT32                    HeadLen;
00230   UINT32                    PacketLen;
00231   UINT32                    Offset;
00232   UINT32                    Mtu;
00233   UINT32                    Num;
00234 
00235   //
00236   // Select an interface/source for system packet, application
00237   // should select them itself.
00238   //
00239   if (IpInstance == NULL) {
00240     IpIf = Ip4SelectInterface (IpSb, Head->Dst, Head->Src);
00241   } else {
00242     IpIf = IpInstance->Interface;
00243   }
00244 
00245   if (IpIf == NULL) {
00246     return EFI_NO_MAPPING;
00247   }
00248 
00249   if ((Head->Src == IP4_ALLZERO_ADDRESS) && (IpInstance == NULL)) {
00250     Head->Src = IpIf->Ip;
00251   }
00252 
00253   //
00254   // Before IPsec process, prepared the IP head.
00255   //
00256   HeadLen        = sizeof (IP4_HEAD) + ((OptLen + 3) & (~0x03));
00257   Head->HeadLen  = (UINT8) (HeadLen >> 2);
00258   Head->Id       = mIp4Id++;
00259   Head->Ver      = 4;
00260   
00261   //
00262   // Call IPsec process.
00263   //
00264   Status = Ip4IpSecProcessPacket (
00265              IpSb, 
00266              &Head, 
00267              &Packet, 
00268              &Option, 
00269              &OptLen, 
00270              EfiIPsecOutBound,
00271              Context
00272              );
00273 
00274   if (EFI_ERROR(Status)) {
00275     return Status;
00276   }
00277 
00278   //
00279   // Route the packet unless overrided, that is, GateWay isn't zero.
00280   //
00281   if (GateWay == IP4_ALLZERO_ADDRESS) {
00282     Dest = Head->Dst;
00283 
00284     if (IP4_IS_BROADCAST (Ip4GetNetCast (Dest, IpIf)) || (Dest == IP4_ALLONE_ADDRESS)) {
00285       //
00286       // Set the gateway to local broadcast if the Dest is
00287       // the broadcast address for the connected network or
00288       // it is local broadcast.
00289       //
00290       GateWay = IP4_ALLONE_ADDRESS;
00291 
00292     } else if (IP4_IS_MULTICAST (Dest)) {
00293       //
00294       // Set the gateway to the destination if it is an multicast
00295       // address. The IP4_INTERFACE won't consult ARP to send local
00296       // broadcast and multicast.
00297       //
00298       GateWay = Head->Dst;
00299 
00300     } else {
00301       //
00302       // Consult the route table to route the packet
00303       //
00304       if (IpInstance == NULL) {
00305         CacheEntry = Ip4Route (IpSb->DefaultRouteTable, Head->Dst, Head->Src);
00306       } else {
00307         CacheEntry = Ip4Route (IpInstance->RouteTable, Head->Dst, Head->Src);
00308       }
00309 
00310       if (CacheEntry == NULL) {
00311         return EFI_NOT_FOUND;
00312       }
00313 
00314       GateWay = CacheEntry->NextHop;
00315       Ip4FreeRouteCacheEntry (CacheEntry);
00316     }
00317   }
00318 
00319   //
00320   // OK, selected the source and route, fragment the packet then send
00321   // them. Tag each fragment other than the first one as spawn from it.
00322   //
00323   Mtu = IpSb->MaxPacketSize + sizeof (IP4_HEAD);  
00324 
00325   if (Packet->TotalSize + HeadLen > Mtu) {
00326     //
00327     // Packet is fragmented from the tail to the head, that is, the
00328     // first frame sent is the last fragment of the packet. The first
00329     // fragment is NOT sent in this loop. First compute how many
00330     // fragments there are.
00331     //
00332     Mtu       = (Mtu - HeadLen) & (~0x07);
00333     Num       = (Packet->TotalSize + Mtu - 1) / Mtu;
00334 
00335     //
00336     // Initialize the packet length and Offset. Other than the last
00337     // fragment, the packet length equals to MTU. The offset is always
00338     // aligned to MTU.
00339     //
00340     PacketLen = Packet->TotalSize - (Num - 1) * Mtu;
00341     Offset    = Mtu * (Num - 1);
00342 
00343     for (Index = 0; Index < Num - 1; Index++, Offset -= Mtu) {
00344       Fragment = NetbufGetFragment (Packet, Offset, PacketLen, IP4_MAX_HEADLEN);
00345 
00346       if (Fragment == NULL) {
00347         Status = EFI_OUT_OF_RESOURCES;
00348         goto ON_ERROR;
00349       }
00350 
00351       //
00352       // Update the header's fragment. The caller fills the IP4 header
00353       // fields that are required by Ip4PrependHead except the fragment.
00354       //
00355       Head->Fragment = IP4_HEAD_FRAGMENT_FIELD (FALSE, (Index != 0), Offset);
00356       Ip4PrependHead (Fragment, Head, Option, OptLen);
00357 
00358       //
00359       // Transmit the fragments, pass the Packet address as the context.
00360       // So, we can find all the fragments spawned from the Packet by
00361       // compare the NetBuf and Context to the Packet.
00362       //
00363       Status = Ip4SendFrame (
00364                  IpIf,
00365                  IpInstance,
00366                  Fragment,
00367                  GateWay,
00368                  Ip4SysPacketSent,
00369                  Packet
00370                  );
00371 
00372       if (EFI_ERROR (Status)) {
00373         goto ON_ERROR;
00374       }
00375 
00376       PacketLen = Mtu;
00377     }
00378 
00379     //
00380     // Trim the already sent data, then adjust the head's fragment field.
00381     //
00382     NetbufTrim (Packet, Packet->TotalSize - Mtu, FALSE);
00383     Head->Fragment = IP4_HEAD_FRAGMENT_FIELD (FALSE, TRUE, 0);
00384   }
00385 
00386   //
00387   // Send the first fragment, it is either the orginal packet, or the
00388   // first fragment of a fragmented packet. It seems that there is a subtle
00389   // bug here: what if the caller free the packet in Callback and IpIf (or
00390   // MNP child used by that interface) still holds the fragments and try
00391   // to access the data? The caller can free the packet if it recycles the
00392   // consumer's (such as UDP) data in the Callback. But this can't happen.
00393   // The detailed sequence is:
00394   // 1. for the packets generated by IP4 driver itself:
00395   //    The Callback is Ip4SysPacketSent, which is the same as the
00396   //    fragments' callback. Ip4SysPacketSent simply calls NetbufFree
00397   //    to release its reference to the packet. So, no problem for
00398   //    system packets.
00399   //
00400   // 2. for the upper layer's packets (use UDP as an example):
00401   //    UDP requests the IP layer to transmit some data which is
00402   //    wrapped in an asynchronous token, the token is wrapped
00403   //    in IP4_TXTOKEN_WRAP by IP4. IP4 also wrap the user's data
00404   //    in a net buffer, which is Packet we get here. IP4_TXTOKEN_WRAP
00405   //    is bound with the Packet. It will only be freed when all
00406   //    the references to Packet have been released. Upon then, the
00407   //    Packet's OnFree callback will release the IP4_TXTOKEN_WRAP,
00408   //    and singal the user's recycle event. So, also no problem for
00409   //    upper layer's packets.
00410   //
00411   Ip4PrependHead (Packet, Head, Option, OptLen);
00412   Status = Ip4SendFrame (IpIf, IpInstance, Packet, GateWay, Callback, Context);
00413 
00414   if (EFI_ERROR (Status)) {
00415     goto ON_ERROR;
00416   }
00417 
00418   return EFI_SUCCESS;
00419 
00420 ON_ERROR:
00421   Ip4CancelPacket (IpIf, Packet, Status);
00422   return Status;
00423 }
00424 
00425 
00437 BOOLEAN
00438 Ip4CancelPacketFragments (
00439   IN IP4_LINK_TX_TOKEN   *Frame,
00440   IN VOID                *Context
00441   )
00442 {
00443   if ((Frame->Packet == (NET_BUF *) Context) || (Frame->Context == Context)) {
00444     return TRUE;
00445   }
00446 
00447   return FALSE;
00448 }
00449 
00450 
00459 VOID
00460 Ip4CancelPacket (
00461   IN IP4_INTERFACE    *IpIf,
00462   IN NET_BUF          *Packet,
00463   IN EFI_STATUS       IoStatus
00464   )
00465 {
00466   Ip4CancelFrames (IpIf, IoStatus, Ip4CancelPacketFragments, Packet);
00467 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Defines