123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- /** @file
- IP4 option support functions.
- Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "Ip4Impl.h"
- /**
- Validate the IP4 option format for both the packets we received
- and will transmit.
- @param[in] Option The first byte of the option
- @param[in] OptionLen The length of the whole option
- @param[in] Rcvd The option is from the packet we received if TRUE,
- otherwise the option we wants to transmit.
- @retval TRUE The option is properly formatted
- @retval FALSE The option is malformatted
- **/
- BOOLEAN
- Ip4OptionIsValid (
- IN UINT8 *Option,
- IN UINT32 OptionLen,
- IN BOOLEAN Rcvd
- )
- {
- UINT32 Cur;
- UINT32 Len;
- UINT32 Point;
- Cur = 0;
- while (Cur < OptionLen) {
- switch (Option[Cur]) {
- case IP4_OPTION_NOP:
- Cur++;
- break;
- case IP4_OPTION_EOP:
- Cur = OptionLen;
- break;
- case IP4_OPTION_LSRR:
- case IP4_OPTION_SSRR:
- case IP4_OPTION_RR:
- Len = Option[Cur + 1];
- Point = Option[Cur + 2];
- //
- // SRR/RR options are formatted as |Type|Len|Point|Ip1|Ip2|...
- //
- if ((OptionLen - Cur < Len) || (Len < 3) || ((Len - 3) % 4 != 0)) {
- return FALSE;
- }
- if ((Point > Len + 1) || (Point % 4 != 0)) {
- return FALSE;
- }
- //
- // The Point must point pass the last entry if the packet is received
- // by us. It must point to 4 if the packet is to be sent by us for
- // source route option.
- //
- if ((Option[Cur] != IP4_OPTION_RR) &&
- ((Rcvd && (Point != Len + 1)) || (!Rcvd && (Point != 4))))
- {
- return FALSE;
- }
- Cur += Len;
- break;
- default:
- Len = Option[Cur + 1];
- if ((OptionLen - Cur < Len) || (Len < 2)) {
- return FALSE;
- }
- Cur = Cur + Len;
- break;
- }
- }
- return TRUE;
- }
- /**
- Copy the option from the original option to buffer. It
- handles the details such as:
- 1. whether copy the single IP4 option to the first/non-first
- fragments.
- 2. Pad the options copied over to aligned to 4 bytes.
- @param[in] Option The original option to copy from
- @param[in] OptionLen The length of the original option
- @param[in] FirstFragment Whether it is the first fragment
- @param[in, out] Buf The buffer to copy options to. NULL
- @param[in, out] BufLen The length of the buffer
- @retval EFI_SUCCESS The options are copied over
- @retval EFI_BUFFER_TOO_SMALL Buf is NULL or BufLen provided is too small.
- **/
- EFI_STATUS
- Ip4CopyOption (
- IN UINT8 *Option,
- IN UINT32 OptionLen,
- IN BOOLEAN FirstFragment,
- IN OUT UINT8 *Buf OPTIONAL,
- IN OUT UINT32 *BufLen
- )
- {
- UINT8 OptBuf[40];
- UINT32 Cur;
- UINT32 Next;
- UINT8 Type;
- UINT32 Len;
- ASSERT ((BufLen != NULL) && (OptionLen <= 40));
- Cur = 0;
- Next = 0;
- while (Cur < OptionLen) {
- Type = Option[Cur];
- Len = Option[Cur + 1];
- if (Type == IP4_OPTION_NOP) {
- //
- // Keep the padding, in case that the sender wants to align
- // the option, say, to 4 bytes
- //
- OptBuf[Next] = IP4_OPTION_NOP;
- Next++;
- Cur++;
- } else if (Type == IP4_OPTION_EOP) {
- //
- // Don't append the EOP to avoid including only a EOP option
- //
- break;
- } else {
- //
- // don't copy options that is only valid for the first fragment
- //
- if (FirstFragment || ((Type & IP4_OPTION_COPY_MASK) != 0)) {
- CopyMem (OptBuf + Next, Option + Cur, Len);
- Next += Len;
- }
- Cur += Len;
- }
- }
- //
- // Don't append an EOP only option.
- //
- if (Next == 0) {
- *BufLen = 0;
- return EFI_SUCCESS;
- }
- //
- // Append an EOP if the end of option doesn't coincide with the
- // end of the IP header, that is, isn't aligned to 4 bytes..
- //
- if ((Next % 4) != 0) {
- OptBuf[Next] = IP4_OPTION_EOP;
- Next++;
- }
- //
- // Head length is in the unit of 4 bytes. Now, Len is the
- // actual option length to appear in the IP header.
- //
- Len = ((Next + 3) &~0x03);
- //
- // If the buffer is too small, set the BufLen then return
- //
- if ((Buf == NULL) || (*BufLen < Len)) {
- *BufLen = Len;
- return EFI_BUFFER_TOO_SMALL;
- }
- //
- // Copy the option to the Buf, zero the buffer first to pad
- // the options with NOP to align to 4 bytes.
- //
- ZeroMem (Buf, Len);
- CopyMem (Buf, OptBuf, Next);
- *BufLen = Len;
- return EFI_SUCCESS;
- }
|