1 /** @file 2 IP4 option support functions. 3 4 Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13 **/ 14 15 #include "Ip4Impl.h" 16 17 18 /** 19 Validate the IP4 option format for both the packets we received 20 and will transmit. 21 22 @param[in] Option The first byte of the option 23 @param[in] OptionLen The length of the whole option 24 @param[in] Rcvd The option is from the packet we received if TRUE, 25 otherwise the option we wants to transmit. 26 27 @retval TRUE The option is properly formatted 28 @retval FALSE The option is mal-formated 29 30 **/ 31 BOOLEAN 32 Ip4OptionIsValid ( 33 IN UINT8 *Option, 34 IN UINT32 OptionLen, 35 IN BOOLEAN Rcvd 36 ) 37 { 38 UINT32 Cur; 39 UINT32 Len; 40 UINT32 Point; 41 42 Cur = 0; 43 44 while (Cur < OptionLen) { 45 switch (Option[Cur]) { 46 case IP4_OPTION_NOP: 47 Cur++; 48 break; 49 50 case IP4_OPTION_EOP: 51 Cur = OptionLen; 52 break; 53 54 case IP4_OPTION_LSRR: 55 case IP4_OPTION_SSRR: 56 case IP4_OPTION_RR: 57 Len = Option[Cur + 1]; 58 Point = Option[Cur + 2]; 59 60 // 61 // SRR/RR options are formatted as |Type|Len|Point|Ip1|Ip2|... 62 // 63 if ((OptionLen - Cur < Len) || (Len < 3) || ((Len - 3) % 4 != 0)) { 64 return FALSE; 65 } 66 67 if ((Point > Len + 1) || (Point % 4 != 0)) { 68 return FALSE; 69 } 70 71 // 72 // The Point must point pass the last entry if the packet is received 73 // by us. It must point to 4 if the packet is to be sent by us for 74 // source route option. 75 // 76 if ((Option[Cur] != IP4_OPTION_RR) && 77 ((Rcvd && (Point != Len + 1)) || (!Rcvd && (Point != 4)))) { 78 79 return FALSE; 80 } 81 82 Cur += Len; 83 break; 84 85 default: 86 Len = Option[Cur + 1]; 87 88 if ((OptionLen - Cur < Len) || (Len < 2)) { 89 return FALSE; 90 } 91 92 Cur = Cur + Len; 93 break; 94 } 95 96 } 97 98 return TRUE; 99 } 100 101 102 /** 103 Copy the option from the original option to buffer. It 104 handles the details such as: 105 1. whether copy the single IP4 option to the first/non-first 106 fragments. 107 2. Pad the options copied over to aligned to 4 bytes. 108 109 @param[in] Option The original option to copy from 110 @param[in] OptionLen The length of the original option 111 @param[in] FirstFragment Whether it is the first fragment 112 @param[in, out] Buf The buffer to copy options to. NULL 113 @param[in, out] BufLen The length of the buffer 114 115 @retval EFI_SUCCESS The options are copied over 116 @retval EFI_BUFFER_TOO_SMALL Buf is NULL or BufLen provided is too small. 117 118 **/ 119 EFI_STATUS 120 Ip4CopyOption ( 121 IN UINT8 *Option, 122 IN UINT32 OptionLen, 123 IN BOOLEAN FirstFragment, 124 IN OUT UINT8 *Buf, OPTIONAL 125 IN OUT UINT32 *BufLen 126 ) 127 { 128 UINT8 OptBuf[40]; 129 UINT32 Cur; 130 UINT32 Next; 131 UINT8 Type; 132 UINT32 Len; 133 134 ASSERT ((BufLen != NULL) && (OptionLen <= 40)); 135 136 Cur = 0; 137 Next = 0; 138 139 while (Cur < OptionLen) { 140 Type = Option[Cur]; 141 Len = Option[Cur + 1]; 142 143 if (Type == IP4_OPTION_NOP) { 144 // 145 // Keep the padding, in case that the sender wants to align 146 // the option, say, to 4 bytes 147 // 148 OptBuf[Next] = IP4_OPTION_NOP; 149 Next++; 150 Cur++; 151 152 } else if (Type == IP4_OPTION_EOP) { 153 // 154 // Don't append the EOP to avoid including only a EOP option 155 // 156 break; 157 158 } else { 159 // 160 // don't copy options that is only valid for the first fragment 161 // 162 if (FirstFragment || (Type & IP4_OPTION_COPY_MASK) != 0) { 163 CopyMem (OptBuf + Next, Option + Cur, Len); 164 Next += Len; 165 } 166 167 Cur += Len; 168 } 169 } 170 171 // 172 // Don't append an EOP only option. 173 // 174 if (Next == 0) { 175 *BufLen = 0; 176 return EFI_SUCCESS; 177 } 178 179 // 180 // Append an EOP if the end of option doesn't coincide with the 181 // end of the IP header, that is, isn't aligned to 4 bytes.. 182 // 183 if ((Next % 4) != 0) { 184 OptBuf[Next] = IP4_OPTION_EOP; 185 Next++; 186 } 187 188 // 189 // Head length is in the unit of 4 bytes. Now, Len is the 190 // acutal option length to appear in the IP header. 191 // 192 Len = ((Next + 3) &~0x03); 193 194 // 195 // If the buffer is too small, set the BufLen then return 196 // 197 if ((Buf == NULL) || (*BufLen < Len)) { 198 *BufLen = Len; 199 return EFI_BUFFER_TOO_SMALL; 200 } 201 202 // 203 // Copy the option to the Buf, zero the buffer first to pad 204 // the options with NOP to align to 4 bytes. 205 // 206 ZeroMem (Buf, Len); 207 CopyMem (Buf, OptBuf, Next); 208 *BufLen = Len; 209 return EFI_SUCCESS; 210 } 211