Line data Source code
1 : /*
2 : * Copyright (c) 2017 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 : /*
16 : * ip/ip4_input.c: IP v4 input node
17 : *
18 : * Copyright (c) 2008 Eliot Dresselhaus
19 : *
20 : * Permission is hereby granted, free of charge, to any person obtaining
21 : * a copy of this software and associated documentation files (the
22 : * "Software"), to deal in the Software without restriction, including
23 : * without limitation the rights to use, copy, modify, merge, publish,
24 : * distribute, sublicense, and/or sell copies of the Software, and to
25 : * permit persons to whom the Software is furnished to do so, subject to
26 : * the following conditions:
27 : *
28 : * The above copyright notice and this permission notice shall be
29 : * included in all copies or substantial portions of the Software.
30 : *
31 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 : * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 : * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 : * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 : * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 : * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 : */
39 :
40 : #ifndef included_ip_input_h
41 : #define included_ip_input_h
42 :
43 : #include <vnet/ip/ip.h>
44 : #include <vnet/ethernet/ethernet.h>
45 : #include <vppinfra/vector/ip_csum.h>
46 :
47 : typedef enum
48 : {
49 : IP4_INPUT_NEXT_DROP,
50 : IP4_INPUT_NEXT_PUNT,
51 : IP4_INPUT_NEXT_OPTIONS,
52 : IP4_INPUT_NEXT_LOOKUP,
53 : IP4_INPUT_NEXT_LOOKUP_MULTICAST,
54 : IP4_INPUT_NEXT_ICMP_ERROR,
55 : IP4_INPUT_N_NEXT,
56 : } ip4_input_next_t;
57 :
58 : static_always_inline void
59 13551747 : check_ver_opt_csum (ip4_header_t * ip, u8 * error, int verify_checksum)
60 : {
61 13551747 : if (PREDICT_FALSE (ip->ip_version_and_header_length != 0x45))
62 : {
63 91 : if ((ip->ip_version_and_header_length & 0xf0) != 0x40)
64 67 : *error = IP4_ERROR_VERSION;
65 24 : else if ((ip->ip_version_and_header_length & 0x0f) < 5)
66 0 : *error = IP4_ERROR_HDR_TOO_SHORT;
67 : else
68 : {
69 24 : *error = IP4_ERROR_OPTIONS;
70 48 : if (verify_checksum &&
71 24 : clib_ip_csum ((u8 *) ip, ip4_header_bytes (ip)) != 0)
72 0 : *error = IP4_ERROR_BAD_CHECKSUM;
73 : }
74 : }
75 13551647 : else if (PREDICT_FALSE (verify_checksum &&
76 : clib_ip_csum ((u8 *) ip, sizeof (ip4_header_t)) !=
77 : 0))
78 197 : *error = IP4_ERROR_BAD_CHECKSUM;
79 13551747 : }
80 :
81 : always_inline void
82 3284680 : ip4_input_check_x4 (vlib_main_t * vm,
83 : vlib_node_runtime_t * error_node,
84 : vlib_buffer_t ** p, ip4_header_t ** ip,
85 : u16 * next, int verify_checksum)
86 : {
87 : u8 error0, error1, error2, error3;
88 : u32 ip_len0, cur_len0;
89 : u32 ip_len1, cur_len1;
90 : u32 ip_len2, cur_len2;
91 : u32 ip_len3, cur_len3;
92 : i32 len_diff0, len_diff1, len_diff2, len_diff3;
93 :
94 3284680 : error0 = error1 = error2 = error3 = IP4_ERROR_NONE;
95 :
96 3284680 : check_ver_opt_csum (ip[0], &error0, verify_checksum);
97 3284680 : check_ver_opt_csum (ip[1], &error1, verify_checksum);
98 3284680 : check_ver_opt_csum (ip[2], &error2, verify_checksum);
99 3284690 : check_ver_opt_csum (ip[3], &error3, verify_checksum);
100 :
101 3284690 : if (PREDICT_FALSE (ip[0]->ttl < 1))
102 0 : error0 = IP4_ERROR_TIME_EXPIRED;
103 3284690 : if (PREDICT_FALSE (ip[1]->ttl < 1))
104 0 : error1 = IP4_ERROR_TIME_EXPIRED;
105 3284690 : if (PREDICT_FALSE (ip[2]->ttl < 1))
106 0 : error2 = IP4_ERROR_TIME_EXPIRED;
107 3284690 : if (PREDICT_FALSE (ip[3]->ttl < 1))
108 0 : error3 = IP4_ERROR_TIME_EXPIRED;
109 :
110 : /* Drop fragmentation offset 1 packets. */
111 3284690 : error0 = ip4_get_fragment_offset (ip[0]) == 1 ?
112 : IP4_ERROR_FRAGMENT_OFFSET_ONE : error0;
113 3284690 : error1 = ip4_get_fragment_offset (ip[1]) == 1 ?
114 : IP4_ERROR_FRAGMENT_OFFSET_ONE : error1;
115 3284690 : error2 = ip4_get_fragment_offset (ip[2]) == 1 ?
116 : IP4_ERROR_FRAGMENT_OFFSET_ONE : error2;
117 3284690 : error3 = ip4_get_fragment_offset (ip[3]) == 1 ?
118 : IP4_ERROR_FRAGMENT_OFFSET_ONE : error3;
119 :
120 : /* Verify lengths. */
121 3284680 : ip_len0 = clib_net_to_host_u16 (ip[0]->length);
122 3284680 : ip_len1 = clib_net_to_host_u16 (ip[1]->length);
123 3284670 : ip_len2 = clib_net_to_host_u16 (ip[2]->length);
124 3284680 : ip_len3 = clib_net_to_host_u16 (ip[3]->length);
125 :
126 : /* IP length must be at least minimal IP header. */
127 3284670 : error0 = ip_len0 < sizeof (ip[0][0]) ? IP4_ERROR_TOO_SHORT : error0;
128 3284670 : error1 = ip_len1 < sizeof (ip[1][0]) ? IP4_ERROR_TOO_SHORT : error1;
129 3284670 : error2 = ip_len2 < sizeof (ip[2][0]) ? IP4_ERROR_TOO_SHORT : error2;
130 3284670 : error3 = ip_len3 < sizeof (ip[3][0]) ? IP4_ERROR_TOO_SHORT : error3;
131 :
132 3284670 : cur_len0 = vlib_buffer_length_in_chain (vm, p[0]);
133 3284680 : cur_len1 = vlib_buffer_length_in_chain (vm, p[1]);
134 3284670 : cur_len2 = vlib_buffer_length_in_chain (vm, p[2]);
135 3284670 : cur_len3 = vlib_buffer_length_in_chain (vm, p[3]);
136 :
137 3284660 : len_diff0 = cur_len0 - ip_len0;
138 3284660 : len_diff1 = cur_len1 - ip_len1;
139 3284660 : len_diff2 = cur_len2 - ip_len2;
140 3284660 : len_diff3 = cur_len3 - ip_len3;
141 :
142 3284660 : error0 = len_diff0 < 0 ? IP4_ERROR_BAD_LENGTH : error0;
143 3284660 : error1 = len_diff1 < 0 ? IP4_ERROR_BAD_LENGTH : error1;
144 3284660 : error2 = len_diff2 < 0 ? IP4_ERROR_BAD_LENGTH : error2;
145 3284660 : error3 = len_diff3 < 0 ? IP4_ERROR_BAD_LENGTH : error3;
146 :
147 3284660 : if (PREDICT_FALSE (error0 != IP4_ERROR_NONE))
148 : {
149 64 : if (error0 == IP4_ERROR_TIME_EXPIRED)
150 : {
151 0 : icmp4_error_set_vnet_buffer (p[0], ICMP4_time_exceeded,
152 : ICMP4_time_exceeded_ttl_exceeded_in_transit,
153 : 0);
154 0 : next[0] = IP4_INPUT_NEXT_ICMP_ERROR;
155 : }
156 : else
157 64 : next[0] = error0 != IP4_ERROR_OPTIONS ?
158 : IP4_INPUT_NEXT_DROP : IP4_INPUT_NEXT_OPTIONS;
159 64 : p[0]->error = error_node->errors[error0];
160 : }
161 3284660 : if (PREDICT_FALSE (error1 != IP4_ERROR_NONE))
162 : {
163 65 : if (error1 == IP4_ERROR_TIME_EXPIRED)
164 : {
165 0 : icmp4_error_set_vnet_buffer (p[1], ICMP4_time_exceeded,
166 : ICMP4_time_exceeded_ttl_exceeded_in_transit,
167 : 0);
168 0 : next[1] = IP4_INPUT_NEXT_ICMP_ERROR;
169 : }
170 : else
171 65 : next[1] = error1 != IP4_ERROR_OPTIONS ?
172 : IP4_INPUT_NEXT_DROP : IP4_INPUT_NEXT_OPTIONS;
173 65 : p[1]->error = error_node->errors[error1];
174 : }
175 3284660 : if (PREDICT_FALSE (error2 != IP4_ERROR_NONE))
176 : {
177 64 : if (error2 == IP4_ERROR_TIME_EXPIRED)
178 : {
179 0 : icmp4_error_set_vnet_buffer (p[2], ICMP4_time_exceeded,
180 : ICMP4_time_exceeded_ttl_exceeded_in_transit,
181 : 0);
182 0 : next[2] = IP4_INPUT_NEXT_ICMP_ERROR;
183 : }
184 : else
185 64 : next[2] = error2 != IP4_ERROR_OPTIONS ?
186 : IP4_INPUT_NEXT_DROP : IP4_INPUT_NEXT_OPTIONS;
187 64 : p[2]->error = error_node->errors[error2];
188 : }
189 3284660 : if (PREDICT_FALSE (error3 != IP4_ERROR_NONE))
190 : {
191 64 : if (error3 == IP4_ERROR_TIME_EXPIRED)
192 : {
193 0 : icmp4_error_set_vnet_buffer (p[3], ICMP4_time_exceeded,
194 : ICMP4_time_exceeded_ttl_exceeded_in_transit,
195 : 0);
196 0 : next[3] = IP4_INPUT_NEXT_ICMP_ERROR;
197 : }
198 : else
199 64 : next[3] = error3 != IP4_ERROR_OPTIONS ?
200 : IP4_INPUT_NEXT_DROP : IP4_INPUT_NEXT_OPTIONS;
201 64 : p[3]->error = error_node->errors[error3];
202 : }
203 3284660 : }
204 :
205 : always_inline void
206 1490 : ip4_input_check_x2 (vlib_main_t * vm,
207 : vlib_node_runtime_t * error_node,
208 : vlib_buffer_t * p0, vlib_buffer_t * p1,
209 : ip4_header_t * ip0, ip4_header_t * ip1,
210 : u32 * next0, u32 * next1, int verify_checksum)
211 : {
212 : u8 error0, error1;
213 : u32 ip_len0, cur_len0;
214 : u32 ip_len1, cur_len1;
215 : i32 len_diff0, len_diff1;
216 :
217 1490 : error0 = error1 = IP4_ERROR_NONE;
218 :
219 1490 : check_ver_opt_csum (ip0, &error0, verify_checksum);
220 1490 : check_ver_opt_csum (ip1, &error1, verify_checksum);
221 :
222 1490 : if (PREDICT_FALSE (ip0->ttl < 1))
223 0 : error0 = IP4_ERROR_TIME_EXPIRED;
224 1490 : if (PREDICT_FALSE (ip1->ttl < 1))
225 0 : error1 = IP4_ERROR_TIME_EXPIRED;
226 :
227 : /* Drop fragmentation offset 1 packets. */
228 1490 : error0 = ip4_get_fragment_offset (ip0) == 1 ?
229 : IP4_ERROR_FRAGMENT_OFFSET_ONE : error0;
230 1490 : error1 = ip4_get_fragment_offset (ip1) == 1 ?
231 : IP4_ERROR_FRAGMENT_OFFSET_ONE : error1;
232 :
233 : /* Verify lengths. */
234 1490 : ip_len0 = clib_net_to_host_u16 (ip0->length);
235 1490 : ip_len1 = clib_net_to_host_u16 (ip1->length);
236 :
237 : /* IP length must be at least minimal IP header. */
238 1490 : error0 = ip_len0 < sizeof (ip0[0]) ? IP4_ERROR_TOO_SHORT : error0;
239 1490 : error1 = ip_len1 < sizeof (ip1[0]) ? IP4_ERROR_TOO_SHORT : error1;
240 :
241 1490 : cur_len0 = vlib_buffer_length_in_chain (vm, p0);
242 1490 : cur_len1 = vlib_buffer_length_in_chain (vm, p1);
243 :
244 1490 : len_diff0 = cur_len0 - ip_len0;
245 1490 : len_diff1 = cur_len1 - ip_len1;
246 :
247 1490 : error0 = len_diff0 < 0 ? IP4_ERROR_BAD_LENGTH : error0;
248 1490 : error1 = len_diff1 < 0 ? IP4_ERROR_BAD_LENGTH : error1;
249 :
250 1490 : if (PREDICT_FALSE (error0 != IP4_ERROR_NONE))
251 : {
252 62 : if (error0 == IP4_ERROR_TIME_EXPIRED)
253 : {
254 0 : icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
255 : ICMP4_time_exceeded_ttl_exceeded_in_transit,
256 : 0);
257 0 : *next0 = IP4_INPUT_NEXT_ICMP_ERROR;
258 : }
259 : else
260 62 : *next0 = error0 != IP4_ERROR_OPTIONS ?
261 62 : IP4_INPUT_NEXT_DROP : IP4_INPUT_NEXT_OPTIONS;
262 62 : p0->error = error_node->errors[error0];
263 : }
264 1490 : if (PREDICT_FALSE (error1 != IP4_ERROR_NONE))
265 : {
266 62 : if (error1 == IP4_ERROR_TIME_EXPIRED)
267 : {
268 0 : icmp4_error_set_vnet_buffer (p1, ICMP4_time_exceeded,
269 : ICMP4_time_exceeded_ttl_exceeded_in_transit,
270 : 0);
271 0 : *next1 = IP4_INPUT_NEXT_ICMP_ERROR;
272 : }
273 : else
274 62 : *next1 = error1 != IP4_ERROR_OPTIONS ?
275 62 : IP4_INPUT_NEXT_DROP : IP4_INPUT_NEXT_OPTIONS;
276 62 : p1->error = error_node->errors[error1];
277 : }
278 1490 : }
279 :
280 : always_inline void
281 410128 : ip4_input_check_x1 (vlib_main_t * vm,
282 : vlib_node_runtime_t * error_node,
283 : vlib_buffer_t * p0,
284 : ip4_header_t * ip0, u32 * next0, int verify_checksum)
285 : {
286 : u32 ip_len0, cur_len0;
287 : i32 len_diff0;
288 : u8 error0;
289 :
290 410128 : error0 = IP4_ERROR_NONE;
291 :
292 410128 : check_ver_opt_csum (ip0, &error0, verify_checksum);
293 :
294 410128 : if (PREDICT_FALSE (ip0->ttl < 1))
295 1 : error0 = IP4_ERROR_TIME_EXPIRED;
296 :
297 : /* Drop fragmentation offset 1 packets. */
298 410128 : error0 = ip4_get_fragment_offset (ip0) == 1 ?
299 : IP4_ERROR_FRAGMENT_OFFSET_ONE : error0;
300 :
301 : /* Verify lengths. */
302 410128 : ip_len0 = clib_net_to_host_u16 (ip0->length);
303 :
304 : /* IP length must be at least minimal IP header. */
305 410128 : error0 = ip_len0 < sizeof (ip0[0]) ? IP4_ERROR_TOO_SHORT : error0;
306 :
307 410128 : cur_len0 = vlib_buffer_length_in_chain (vm, p0);
308 :
309 410128 : len_diff0 = cur_len0 - ip_len0;
310 :
311 410128 : error0 = len_diff0 < 0 ? IP4_ERROR_BAD_LENGTH : error0;
312 :
313 410128 : if (PREDICT_FALSE (error0 != IP4_ERROR_NONE))
314 : {
315 43 : if (error0 == IP4_ERROR_TIME_EXPIRED)
316 : {
317 1 : icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
318 : ICMP4_time_exceeded_ttl_exceeded_in_transit,
319 : 0);
320 1 : *next0 = IP4_INPUT_NEXT_ICMP_ERROR;
321 : }
322 : else
323 42 : *next0 = error0 != IP4_ERROR_OPTIONS ?
324 42 : IP4_INPUT_NEXT_DROP : IP4_INPUT_NEXT_OPTIONS;
325 43 : p0->error = error_node->errors[error0];
326 : }
327 410128 : }
328 :
329 : /*
330 : * fd.io coding-style-patch-verification: ON
331 : *
332 : * Local Variables:
333 : * eval: (c-set-style "gnu")
334 : * End:
335 : */
336 :
337 : #endif
|