Home | History | Annotate | Download | only in Ip4Dxe
      1 /** @file
      2 
      3 Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>
      4 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 **/
     13 
     14 #include "Ip4Impl.h"
     15 
     16 IP4_ICMP_CLASS
     17 mIcmpClass[] = {
     18   {ICMP_ECHO_REPLY,         ICMP_QUERY_MESSAGE  },
     19   {1,                       ICMP_INVALID_MESSAGE},
     20   {2,                       ICMP_INVALID_MESSAGE},
     21   {ICMP_DEST_UNREACHABLE,   ICMP_ERROR_MESSAGE  },
     22   {ICMP_SOURCE_QUENCH,      ICMP_ERROR_MESSAGE  },
     23   {ICMP_REDIRECT,           ICMP_ERROR_MESSAGE  },
     24   {6,                       ICMP_INVALID_MESSAGE},
     25   {7,                       ICMP_INVALID_MESSAGE},
     26   {ICMP_ECHO_REQUEST,       ICMP_QUERY_MESSAGE  },
     27   {9,                       ICMP_INVALID_MESSAGE},
     28   {10,                      ICMP_INVALID_MESSAGE},
     29   {ICMP_TIME_EXCEEDED,      ICMP_ERROR_MESSAGE  },
     30   {ICMP_PARAMETER_PROBLEM,  ICMP_ERROR_MESSAGE  },
     31   {ICMP_TIMESTAMP ,         ICMP_QUERY_MESSAGE  },
     32   {14,                      ICMP_INVALID_MESSAGE},
     33   {ICMP_INFO_REQUEST ,      ICMP_QUERY_MESSAGE  },
     34   {ICMP_INFO_REPLY ,        ICMP_QUERY_MESSAGE  },
     35 };
     36 
     37 EFI_IP4_ICMP_TYPE
     38 mIp4SupportedIcmp[23] = {
     39   {ICMP_ECHO_REPLY,        ICMP_DEFAULT_CODE        },
     40 
     41   {ICMP_DEST_UNREACHABLE,  ICMP_NET_UNREACHABLE     },
     42   {ICMP_DEST_UNREACHABLE,  ICMP_HOST_UNREACHABLE    },
     43   {ICMP_DEST_UNREACHABLE,  ICMP_PROTO_UNREACHABLE   },
     44   {ICMP_DEST_UNREACHABLE,  ICMP_PORT_UNREACHABLE    },
     45   {ICMP_DEST_UNREACHABLE,  ICMP_FRAGMENT_FAILED     },
     46   {ICMP_DEST_UNREACHABLE,  ICMP_SOURCEROUTE_FAILED  },
     47   {ICMP_DEST_UNREACHABLE,  ICMP_NET_UNKNOWN         },
     48   {ICMP_DEST_UNREACHABLE,  ICMP_HOST_UNKNOWN        },
     49   {ICMP_DEST_UNREACHABLE,  ICMP_SOURCE_ISOLATED     },
     50   {ICMP_DEST_UNREACHABLE,  ICMP_NET_PROHIBITED      },
     51   {ICMP_DEST_UNREACHABLE,  ICMP_HOST_PROHIBITED     },
     52   {ICMP_DEST_UNREACHABLE,  ICMP_NET_UNREACHABLE_TOS },
     53   {ICMP_DEST_UNREACHABLE,  ICMP_HOST_UNREACHABLE_TOS},
     54 
     55   {ICMP_SOURCE_QUENCH,     ICMP_DEFAULT_CODE        },
     56 
     57   {ICMP_REDIRECT,          ICMP_NET_REDIRECT        },
     58   {ICMP_REDIRECT,          ICMP_HOST_REDIRECT       },
     59   {ICMP_REDIRECT,          ICMP_NET_TOS_REDIRECT    },
     60   {ICMP_REDIRECT,          ICMP_HOST_TOS_REDIRECT   },
     61 
     62   {ICMP_ECHO_REQUEST,      ICMP_DEFAULT_CODE        },
     63 
     64   {ICMP_TIME_EXCEEDED,     ICMP_TIMEOUT_IN_TRANSIT  },
     65   {ICMP_TIME_EXCEEDED,     ICMP_TIMEOUT_REASSEMBLE  },
     66 
     67   {ICMP_PARAMETER_PROBLEM, ICMP_DEFAULT_CODE        },
     68 };
     69 
     70 
     71 
     72 /**
     73   Process the ICMP redirect. Find the instance then update
     74   its route cache.
     75 
     76   All kinds of redirect is treated as host redirect as
     77   specified by RFC1122 3.3.1.2:
     78   "Since the subnet mask appropriate to the destination
     79   address is generally not known, a Network Redirect
     80   message SHOULD be treated identically to a Host Redirect
     81   message;"
     82 
     83   @param[in]  IpSb               The IP4 service binding instance that received
     84                                  the packet.
     85   @param[in]  Head               The IP head of the received ICMPpacket.
     86   @param[in]  Packet             The content of the ICMP redirect packet with IP
     87                                  head removed.
     88   @param[in]  Icmp               The buffer to store the ICMP error message if
     89                                  something is wrong.
     90 
     91   @retval EFI_INVALID_PARAMETER  The parameter is invalid
     92   @retval EFI_SUCCESS            Successfully updated the route caches
     93 
     94 **/
     95 EFI_STATUS
     96 Ip4ProcessIcmpRedirect (
     97   IN IP4_SERVICE            *IpSb,
     98   IN IP4_HEAD               *Head,
     99   IN NET_BUF                *Packet,
    100   IN IP4_ICMP_ERROR_HEAD    *Icmp
    101   )
    102 {
    103   LIST_ENTRY                *Entry;
    104   IP4_PROTOCOL              *Ip4Instance;
    105   IP4_ROUTE_CACHE_ENTRY     *CacheEntry;
    106   IP4_INTERFACE             *IpIf;
    107   IP4_ADDR                  Gateway;
    108   IP4_ADDR                  Src;
    109   IP4_ADDR                  Dst;
    110 
    111   //
    112   // Find the interface whose IP address is the source of the
    113   // orgianl IP packet.
    114   //
    115   IpIf    = Ip4FindInterface (IpSb, NTOHL (Icmp->IpHead.Src));
    116   Gateway = NTOHL (Icmp->Fourth);
    117 
    118   //
    119   // discard the packet if the new gateway address it specifies
    120   // is not on the same connected net through which the Redirect
    121   // arrived. (RFC1122 3.2.2.2).
    122   //
    123   if ((IpIf == NULL) || !IP4_NET_EQUAL (Gateway, IpIf->Ip, IpIf->SubnetMask)) {
    124     NetbufFree (Packet);
    125     return EFI_INVALID_PARAMETER;
    126   }
    127 
    128   //
    129   // Update each IP child's route cache on the interface.
    130   //
    131   NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {
    132     Ip4Instance = NET_LIST_USER_STRUCT (Entry, IP4_PROTOCOL, AddrLink);
    133 
    134     if (Ip4Instance->RouteTable == NULL) {
    135       continue;
    136     }
    137 
    138     Dst = NTOHL (Icmp->IpHead.Dst);
    139     Src = NTOHL (Icmp->IpHead.Src);
    140     CacheEntry = Ip4FindRouteCache (Ip4Instance->RouteTable, Dst, Src);
    141 
    142     //
    143     // Only update the route cache's gateway if the source of the
    144     // Redirect is the current first-hop gateway
    145     //
    146     if ((CacheEntry != NULL) && (NTOHL (Head->Src) == CacheEntry->NextHop)) {
    147       CacheEntry->NextHop = Gateway;
    148     }
    149   }
    150 
    151   NetbufFree (Packet);
    152   return EFI_SUCCESS;
    153 }
    154 
    155 
    156 /**
    157   Process the ICMP error packet. If it is an ICMP redirect packet,
    158   update call Ip4ProcessIcmpRedirect to update the IP instance's
    159   route cache, otherwise, deliver the packet to upper layer.
    160 
    161   @param[in]  IpSb               The IP4 service that received the packet.
    162   @param[in]  Head               The IP4 head of the ICMP error packet
    163   @param[in]  Packet             The content of the ICMP error with IP4 head
    164                                  removed.
    165 
    166   @retval EFI_SUCCESS            The ICMP error is processed successfully.
    167   @retval EFI_INVALID_PARAMETER  The packet is invalid
    168   @retval Others                 Failed to process the packet.
    169 
    170 **/
    171 EFI_STATUS
    172 Ip4ProcessIcmpError (
    173   IN IP4_SERVICE            *IpSb,
    174   IN IP4_HEAD               *Head,
    175   IN NET_BUF                *Packet
    176   )
    177 {
    178   IP4_ICMP_ERROR_HEAD       Icmp;
    179 
    180   if (Packet->TotalSize < sizeof (Icmp)) {
    181     NetbufFree (Packet);
    182     return EFI_INVALID_PARAMETER;
    183   }
    184 
    185   NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
    186 
    187   //
    188   // If it is an ICMP redirect error, update the route cache
    189   // as RFC1122. Otherwise, demultiplex it to IP instances.
    190   //
    191   if (Icmp.Head.Type == ICMP_REDIRECT) {
    192     return Ip4ProcessIcmpRedirect (IpSb, Head, Packet, &Icmp);
    193   }
    194 
    195   IP4_GET_CLIP_INFO (Packet)->Status = EFI_ICMP_ERROR;
    196   return Ip4Demultiplex (IpSb, Head, Packet, NULL, 0);
    197 }
    198 
    199 
    200 /**
    201   Replay an ICMP echo request.
    202 
    203   @param[in]  IpSb               The IP4 service that receivd the packet
    204   @param[in]  Head               The IP4 head of the ICMP error packet
    205   @param[in]  Packet             The content of the ICMP error with IP4 head
    206                                  removed.
    207 
    208   @retval EFI_OUT_OF_RESOURCES   Failed to allocate resource.
    209   @retval EFI_SUCCESS            The ICMP Echo request is successfully answered.
    210   @retval Others                 Failed to answer the ICMP echo request.
    211 
    212 **/
    213 EFI_STATUS
    214 Ip4IcmpReplyEcho (
    215   IN IP4_SERVICE            *IpSb,
    216   IN IP4_HEAD               *Head,
    217   IN NET_BUF                *Packet
    218   )
    219 {
    220   IP4_ICMP_QUERY_HEAD       *Icmp;
    221   NET_BUF                   *Data;
    222   EFI_STATUS                Status;
    223   IP4_HEAD                  ReplyHead;
    224 
    225   //
    226   // make a copy the packet, it is really a bad idea to
    227   // send the MNP's buffer back to MNP.
    228   //
    229   Data = NetbufDuplicate (Packet, NULL, IP4_MAX_HEADLEN);
    230 
    231   if (Data == NULL) {
    232     Status = EFI_OUT_OF_RESOURCES;
    233     goto ON_EXIT;
    234   }
    235 
    236   //
    237   // Change the ICMP type to echo reply, exchange the source
    238   // and destination, then send it. The source is updated to
    239   // use specific destination. See RFC1122. SRR/RR option
    240   // update is omitted.
    241   //
    242   Icmp                = (IP4_ICMP_QUERY_HEAD *) NetbufGetByte (Data, 0, NULL);
    243   ASSERT (Icmp != NULL);
    244   Icmp->Head.Type     = ICMP_ECHO_REPLY;
    245   Icmp->Head.Checksum = 0;
    246   Icmp->Head.Checksum = (UINT16) (~NetblockChecksum ((UINT8 *) Icmp, Data->TotalSize));
    247 
    248   ReplyHead.Tos       = 0;
    249   ReplyHead.Fragment  = 0;
    250   ReplyHead.Ttl       = 64;
    251   ReplyHead.Protocol  = EFI_IP_PROTO_ICMP;
    252   ReplyHead.Src       = 0;
    253 
    254   //
    255   // Ip4Output will select a source for us
    256   //
    257   ReplyHead.Dst = Head->Src;
    258 
    259   Status = Ip4Output (
    260              IpSb,
    261              NULL,
    262              Data,
    263              &ReplyHead,
    264              NULL,
    265              0,
    266              IP4_ALLZERO_ADDRESS,
    267              Ip4SysPacketSent,
    268              NULL
    269              );
    270 
    271 ON_EXIT:
    272   NetbufFree (Packet);
    273   return Status;
    274 }
    275 
    276 
    277 /**
    278   Process the ICMP query message. If it is an ICMP echo
    279   request, answer it. Otherwise deliver it to upper layer.
    280 
    281   @param[in]  IpSb               The IP4 service that receivd the packet
    282   @param[in]  Head               The IP4 head of the ICMP query packet
    283   @param[in]  Packet             The content of the ICMP query with IP4 head
    284                                  removed.
    285 
    286   @retval EFI_INVALID_PARAMETER  The packet is invalid
    287   @retval EFI_SUCCESS            The ICMP query message is processed
    288   @retval Others                 Failed to process ICMP query.
    289 
    290 **/
    291 EFI_STATUS
    292 Ip4ProcessIcmpQuery (
    293   IN IP4_SERVICE            *IpSb,
    294   IN IP4_HEAD               *Head,
    295   IN NET_BUF                *Packet
    296   )
    297 {
    298   IP4_ICMP_QUERY_HEAD       Icmp;
    299 
    300   if (Packet->TotalSize < sizeof (Icmp)) {
    301     NetbufFree (Packet);
    302     return EFI_INVALID_PARAMETER;
    303   }
    304 
    305   NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
    306 
    307   if (Icmp.Head.Type == ICMP_ECHO_REQUEST) {
    308     return Ip4IcmpReplyEcho (IpSb, Head, Packet);
    309   }
    310 
    311   return Ip4Demultiplex (IpSb, Head, Packet, NULL, 0);
    312 }
    313 
    314 
    315 /**
    316   Handle the ICMP packet. First validate the message format,
    317   then according to the message types, process it as query or
    318   error packet.
    319 
    320   @param[in]  IpSb               The IP4 service that receivd the packet.
    321   @param[in]  Head               The IP4 head of the ICMP query packet.
    322   @param[in]  Packet             The content of the ICMP query with IP4 head
    323                                  removed.
    324 
    325   @retval EFI_INVALID_PARAMETER  The packet is malformated.
    326   @retval EFI_SUCCESS            The ICMP message is successfully processed.
    327   @retval Others                 Failed to handle ICMP packet.
    328 
    329 **/
    330 EFI_STATUS
    331 Ip4IcmpHandle (
    332   IN IP4_SERVICE            *IpSb,
    333   IN IP4_HEAD               *Head,
    334   IN NET_BUF                *Packet
    335   )
    336 {
    337   IP4_ICMP_HEAD             Icmp;
    338   UINT16                    Checksum;
    339 
    340   if (Packet->TotalSize < sizeof (Icmp)) {
    341     goto DROP;
    342   }
    343 
    344   NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
    345 
    346   if (Icmp.Type > ICMP_TYPE_MAX) {
    347     goto DROP;
    348   }
    349 
    350   Checksum = (UINT16) (~NetbufChecksum (Packet));
    351   if ((Icmp.Checksum != 0) && (Checksum != 0)) {
    352     goto DROP;
    353   }
    354 
    355   if (mIcmpClass[Icmp.Type].IcmpClass == ICMP_ERROR_MESSAGE) {
    356     return Ip4ProcessIcmpError (IpSb, Head, Packet);
    357 
    358   } else if (mIcmpClass[Icmp.Type].IcmpClass == ICMP_QUERY_MESSAGE) {
    359     return Ip4ProcessIcmpQuery (IpSb, Head, Packet);
    360 
    361   }
    362 
    363 DROP:
    364   NetbufFree (Packet);
    365   return EFI_INVALID_PARAMETER;
    366 }
    367