1/** @file
2  IP4 option support functions.
3
4Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution.  The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT 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**/
31BOOLEAN
32Ip4OptionIsValid (
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**/
119EFI_STATUS
120Ip4CopyOption (
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