1cb9cadadSEd Warnicke/*
2cb9cadadSEd Warnicke * Copyright (c) 2015 Cisco and/or its affiliates.
3cb9cadadSEd Warnicke * Licensed under the Apache License, Version 2.0 (the "License");
4cb9cadadSEd Warnicke * you may not use this file except in compliance with the License.
5cb9cadadSEd Warnicke * You may obtain a copy of the License at:
6cb9cadadSEd Warnicke *
7cb9cadadSEd Warnicke *     http://www.apache.org/licenses/LICENSE-2.0
8cb9cadadSEd Warnicke *
9cb9cadadSEd Warnicke * Unless required by applicable law or agreed to in writing, software
10cb9cadadSEd Warnicke * distributed under the License is distributed on an "AS IS" BASIS,
11cb9cadadSEd Warnicke * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12cb9cadadSEd Warnicke * See the License for the specific language governing permissions and
13cb9cadadSEd Warnicke * limitations under the License.
14cb9cadadSEd Warnicke */
15cb9cadadSEd Warnicke/*
16cb9cadadSEd Warnicke * ip4/packet.h: ip4 packet format
17cb9cadadSEd Warnicke *
18cb9cadadSEd Warnicke * Copyright (c) 2008 Eliot Dresselhaus
19cb9cadadSEd Warnicke *
20cb9cadadSEd Warnicke * Permission is hereby granted, free of charge, to any person obtaining
21cb9cadadSEd Warnicke * a copy of this software and associated documentation files (the
22cb9cadadSEd Warnicke * "Software"), to deal in the Software without restriction, including
23cb9cadadSEd Warnicke * without limitation the rights to use, copy, modify, merge, publish,
24cb9cadadSEd Warnicke * distribute, sublicense, and/or sell copies of the Software, and to
25cb9cadadSEd Warnicke * permit persons to whom the Software is furnished to do so, subject to
26cb9cadadSEd Warnicke * the following conditions:
27cb9cadadSEd Warnicke *
28cb9cadadSEd Warnicke * The above copyright notice and this permission notice shall be
29cb9cadadSEd Warnicke * included in all copies or substantial portions of the Software.
30cb9cadadSEd Warnicke *
38cb9cadadSEd Warnicke */
39cb9cadadSEd Warnicke
40cb9cadadSEd Warnicke#ifndef included_ip4_packet_h
41cb9cadadSEd Warnicke#define included_ip4_packet_h
42cb9cadadSEd Warnicke
43cb9cadadSEd Warnicke#include <vnet/ip/ip_packet.h>	/* for ip_csum_t */
4468b0fb0cSDave Barach#include <vnet/tcp/tcp_packet.h>	/* for tcp_header_t */
45cb9cadadSEd Warnicke#include <vppinfra/byte_order.h>	/* for clib_net_to_host_u16 */
46cb9cadadSEd Warnicke
47cb9cadadSEd Warnicke/* IP4 address which can be accessed either as 4 bytes
48cb9cadadSEd Warnicke   or as a 32-bit number. */
49d7cb1b5fSDave Barachtypedef union
50d7cb1b5fSDave Barach{
51cb9cadadSEd Warnicke  u8 data[4];
52cb9cadadSEd Warnicke  u32 data_u32;
53cb9cadadSEd Warnicke  /* Aliases. */
54cb9cadadSEd Warnicke  u8 as_u8[4];
55a3af337eSNeale Ranns  u16 as_u16[2];
56cb9cadadSEd Warnicke  u32 as_u32;
57cb9cadadSEd Warnicke} ip4_address_t;
58cb9cadadSEd Warnicke
59d7cb1b5fSDave Barachtypedef struct
60d7cb1b5fSDave Barach{
61cb9cadadSEd Warnicke  /* IP address must be first for ip_interface_address_get_address() to work */
62cb9cadadSEd Warnicke  ip4_address_t ip4_addr;
63cb9cadadSEd Warnicke  u32 fib_index;
64cb9cadadSEd Warnicke} ip4_address_fib_t;
65cb9cadadSEd Warnicke
66cb9cadadSEd Warnickealways_inline void
67d69f4396SNeale Rannsip4_addr_fib_init (ip4_address_fib_t * addr_fib,
68d69f4396SNeale Ranns		   const ip4_address_t * address, u32 fib_index)
69cb9cadadSEd Warnicke{
70178cf493SDave Barach  clib_memcpy_fast (&addr_fib->ip4_addr, address,
71178cf493SDave Barach		    sizeof (addr_fib->ip4_addr));
72cb9cadadSEd Warnicke  addr_fib->fib_index = fib_index;
73cb9cadadSEd Warnicke}
74cb9cadadSEd Warnicke
75cb9cadadSEd Warnicke/* (src,dst) pair of addresses as found in packet header. */
76d7cb1b5fSDave Barachtypedef struct
77d7cb1b5fSDave Barach{
78cb9cadadSEd Warnicke  ip4_address_t src, dst;
79cb9cadadSEd Warnicke} ip4_address_pair_t;
80cb9cadadSEd Warnicke
81a35cc14dSDamjan Mariontypedef struct
82a35cc14dSDamjan Marion{
83a35cc14dSDamjan Marion  ip4_address_t addr, mask;
84a35cc14dSDamjan Marion} ip4_address_and_mask_t;
85a35cc14dSDamjan Marion
86cb9cadadSEd Warnicke/* If address is a valid netmask, return length of mask. */
87cb9cadadSEd Warnickealways_inline uword
88d69f4396SNeale Rannsip4_address_netmask_length (const ip4_address_t * a)
89cb9cadadSEd Warnicke{
90cb9cadadSEd Warnicke  uword result = 0;
91cb9cadadSEd Warnicke  uword i;
92cb9cadadSEd Warnicke  for (i = 0; i < ARRAY_LEN (a->as_u8); i++)
93cb9cadadSEd Warnicke    {
94cb9cadadSEd Warnicke      switch (a->as_u8[i])
95cb9cadadSEd Warnicke	{
96d7cb1b5fSDave Barach	case 0xff:
97d7cb1b5fSDave Barach	  result += 8;
98d7cb1b5fSDave Barach	  break;
99d7cb1b5fSDave Barach	case 0xfe:
100d7cb1b5fSDave Barach	  result += 7;
101d7cb1b5fSDave Barach	  goto done;
102d7cb1b5fSDave Barach	case 0xfc:
103d7cb1b5fSDave Barach	  result += 6;
104d7cb1b5fSDave Barach	  goto done;
105d7cb1b5fSDave Barach	case 0xf8:
106d7cb1b5fSDave Barach	  result += 5;
107d7cb1b5fSDave Barach	  goto done;
108d7cb1b5fSDave Barach	case 0xf0:
109d7cb1b5fSDave Barach	  result += 4;
110d7cb1b5fSDave Barach	  goto done;
111d7cb1b5fSDave Barach	case 0xe0:
112d7cb1b5fSDave Barach	  result += 3;
113d7cb1b5fSDave Barach	  goto done;
114d7cb1b5fSDave Barach	case 0xc0:
115d7cb1b5fSDave Barach	  result += 2;
116d7cb1b5fSDave Barach	  goto done;
117d7cb1b5fSDave Barach	case 0x80:
118d7cb1b5fSDave Barach	  result += 1;
119d7cb1b5fSDave Barach	  goto done;
120d7cb1b5fSDave Barach	case 0x00:
121d7cb1b5fSDave Barach	  result += 0;
122d7cb1b5fSDave Barach	  goto done;
123cb9cadadSEd Warnicke	default:
124cb9cadadSEd Warnicke	  /* Not a valid netmask mask. */
125cb9cadadSEd Warnicke	  return ~0;
126cb9cadadSEd Warnicke	}
127cb9cadadSEd Warnicke    }
128d7cb1b5fSDave Barachdone:
129cb9cadadSEd Warnicke  return result;
130cb9cadadSEd Warnicke}
131cb9cadadSEd Warnicke
132d7cb1b5fSDave Barachtypedef union
133d7cb1b5fSDave Barach{
134d7cb1b5fSDave Barach  struct
135d7cb1b5fSDave Barach  {
136cb9cadadSEd Warnicke    /* 4 bit packet length (in 32bit units) and version VVVVLLLL.
137cb9cadadSEd Warnicke       e.g. for packets w/ no options ip_version_and_header_length == 0x45. */
138cb9cadadSEd Warnicke    u8 ip_version_and_header_length;
139cb9cadadSEd Warnicke
140cb9cadadSEd Warnicke    /* Type of service. */
141038e1dfbSNeale Ranns    ip_dscp_t tos;
142cb9cadadSEd Warnicke
143cb9cadadSEd Warnicke    /* Total layer 3 packet length including this header. */
144cb9cadadSEd Warnicke    u16 length;
145cb9cadadSEd Warnicke
146cb9cadadSEd Warnicke    /* Fragmentation ID. */
147cb9cadadSEd Warnicke    u16 fragment_id;
148cb9cadadSEd Warnicke
149cb9cadadSEd Warnicke    /* 3 bits of flags and 13 bits of fragment offset (in units
150cb9cadadSEd Warnicke       of 8 byte quantities). */
151cb9cadadSEd Warnicke    u16 flags_and_fragment_offset;
152cb9cadadSEd Warnicke#define IP4_HEADER_FLAG_MORE_FRAGMENTS (1 << 13)
153cb9cadadSEd Warnicke#define IP4_HEADER_FLAG_DONT_FRAGMENT (1 << 14)
154cb9cadadSEd Warnicke#define IP4_HEADER_FLAG_CONGESTION (1 << 15)
155cb9cadadSEd Warnicke
156cb9cadadSEd Warnicke    /* Time to live decremented by router at each hop. */
157cb9cadadSEd Warnicke    u8 ttl;
158cb9cadadSEd Warnicke
159cb9cadadSEd Warnicke    /* Next level protocol packet. */
160cb9cadadSEd Warnicke    u8 protocol;
161cb9cadadSEd Warnicke
162cb9cadadSEd Warnicke    /* Checksum. */
163cb9cadadSEd Warnicke    u16 checksum;
164cb9cadadSEd Warnicke
165cb9cadadSEd Warnicke    /* Source and destination address. */
166d7cb1b5fSDave Barach    union
167d7cb1b5fSDave Barach    {
168d7cb1b5fSDave Barach      struct
169d7cb1b5fSDave Barach      {
170cb9cadadSEd Warnicke	ip4_address_t src_address, dst_address;
171cb9cadadSEd Warnicke      };
172cb9cadadSEd Warnicke      ip4_address_pair_t address_pair;
173d7cb1b5fSDave Barach    };
174cb9cadadSEd Warnicke  };
175cb9cadadSEd Warnicke
176cb9cadadSEd Warnicke  /* For checksumming we'll want to access IP header in word sized chunks. */
177cb9cadadSEd Warnicke  /* For 64 bit machines. */
178d7cb1b5fSDave Barach  /* *INDENT-OFF* */
179cb9cadadSEd Warnicke  CLIB_PACKED (struct {
180cb9cadadSEd Warnicke    u64 checksum_data_64[2];
181cb9cadadSEd Warnicke    u32 checksum_data_64_32[1];
182cb9cadadSEd Warnicke  });
183d7cb1b5fSDave Barach  /* *INDENT-ON* */
184cb9cadadSEd Warnicke
185cb9cadadSEd Warnicke  /* For 32 bit machines. */
186d7cb1b5fSDave Barach  /* *INDENT-OFF* */
187cb9cadadSEd Warnicke  CLIB_PACKED (struct {
188cb9cadadSEd Warnicke    u32 checksum_data_32[5];
189cb9cadadSEd Warnicke  });
190d7cb1b5fSDave Barach  /* *INDENT-ON* */
191cb9cadadSEd Warnicke} ip4_header_t;
192cb9cadadSEd Warnicke
193cb9cadadSEd Warnicke/* Value of ip_version_and_header_length for packets w/o options. */
194cb9cadadSEd Warnicke#define IP4_VERSION_AND_HEADER_LENGTH_NO_OPTIONS \
195cb9cadadSEd Warnicke  ((4 << 4) | (sizeof (ip4_header_t) / sizeof (u32)))
196cb9cadadSEd Warnicke
197c667ffd4SNeale Ranns#define IP4_ROUTER_ALERT_OPTION 20
198c667ffd4SNeale Ranns
199f126e746SKlement Sekeraalways_inline u16
200d69f4396SNeale Rannsip4_get_fragment_offset (const ip4_header_t * i)
201d7cb1b5fSDave Barach{
202d7cb1b5fSDave Barach  return clib_net_to_host_u16 (i->flags_and_fragment_offset) & 0x1fff;
203d7cb1b5fSDave Barach}
204cb9cadadSEd Warnicke
205f126e746SKlement Sekeraalways_inline u16
206d69f4396SNeale Rannsip4_get_fragment_more (const ip4_header_t * i)
207d7cb1b5fSDave Barach{
208d7cb1b5fSDave Barach  return clib_net_to_host_u16 (i->flags_and_fragment_offset) &
209d7cb1b5fSDave Barach    IP4_HEADER_FLAG_MORE_FRAGMENTS;
210d7cb1b5fSDave Barach}
211cb9cadadSEd Warnicke
212cb9cadadSEd Warnickealways_inline int
213d69f4396SNeale Rannsip4_is_fragment (const ip4_header_t * i)
214d7cb1b5fSDave Barach{
215d7cb1b5fSDave Barach  return (i->flags_and_fragment_offset &
216d7cb1b5fSDave Barach	  clib_net_to_host_u16 (0x1fff | IP4_HEADER_FLAG_MORE_FRAGMENTS));
217d7cb1b5fSDave Barach}
218cb9cadadSEd Warnicke
219cb9cadadSEd Warnickealways_inline int
220d69f4396SNeale Rannsip4_is_first_fragment (const ip4_header_t * i)
221d7cb1b5fSDave Barach{
222d7cb1b5fSDave Barach  return (i->flags_and_fragment_offset &
223d7cb1b5fSDave Barach	  clib_net_to_host_u16 (0x1fff | IP4_HEADER_FLAG_MORE_FRAGMENTS)) ==
224d7cb1b5fSDave Barach    clib_net_to_host_u16 (IP4_HEADER_FLAG_MORE_FRAGMENTS);
225d7cb1b5fSDave Barach}
226cb9cadadSEd Warnicke
227cb9cadadSEd Warnicke/* Fragment offset in bytes. */
228cb9cadadSEd Warnickealways_inline int
229d69f4396SNeale Rannsip4_get_fragment_offset_bytes (const ip4_header_t * i)
230d7cb1b5fSDave Barach{
231d7cb1b5fSDave Barach  return 8 * ip4_get_fragment_offset (i);
232d7cb1b5fSDave Barach}
233cb9cadadSEd Warnicke
234cb9cadadSEd Warnickealways_inline int
235d69f4396SNeale Rannsip4_header_bytes (const ip4_header_t * i)
236d7cb1b5fSDave Barach{
237d7cb1b5fSDave Barach  return sizeof (u32) * (i->ip_version_and_header_length & 0xf);
238d7cb1b5fSDave Barach}
239cb9cadadSEd Warnicke
240cb9cadadSEd Warnickealways_inline void *
241cb9cadadSEd Warnickeip4_next_header (ip4_header_t * i)
242d7cb1b5fSDave Barach{
243d7cb1b5fSDave Barach  return (void *) i + ip4_header_bytes (i);
244d7cb1b5fSDave Barach}
245cb9cadadSEd Warnicke
246cb9cadadSEd Warnickealways_inline u16
247cb9cadadSEd Warnickeip4_header_checksum (ip4_header_t * i)
248cb9cadadSEd Warnicke{
249cb9cadadSEd Warnicke  u16 save, csum;
250cb9cadadSEd Warnicke  ip_csum_t sum;
251cb9cadadSEd Warnicke
252cb9cadadSEd Warnicke  save = i->checksum;
253cb9cadadSEd Warnicke  i->checksum = 0;
254cb9cadadSEd Warnicke  sum = ip_incremental_checksum (0, i, ip4_header_bytes (i));
255cb9cadadSEd Warnicke  csum = ~ip_csum_fold (sum);
256cb9cadadSEd Warnicke
257cb9cadadSEd Warnicke  i->checksum = save;
258cb9cadadSEd Warnicke
259cb9cadadSEd Warnicke  /* Make checksum agree for special case where either
260cb9cadadSEd Warnicke     0 or 0xffff would give same 1s complement sum. */
261cb9cadadSEd Warnicke  if (csum == 0 && save == 0xffff)
262cb9cadadSEd Warnicke    csum = save;
263cb9cadadSEd Warnicke
264cb9cadadSEd Warnicke  return csum;
265cb9cadadSEd Warnicke}
266cb9cadadSEd Warnicke
2679534696bSNeale Rannsalways_inline void
2689534696bSNeale Rannsip4_header_set_dscp (ip4_header_t * ip4, ip_dscp_t dscp)
2699534696bSNeale Ranns{
2709534696bSNeale Ranns  ip4->tos &= ~0xfc;
2719534696bSNeale Ranns  /* not masking the dscp value to save th instruction
2729534696bSNeale Ranns   * it shouldn't b necessary since the argument is an enum
2739534696bSNeale Ranns   * whose range is therefore constrained in the CP. in the
2749534696bSNeale Ranns   * DP it will have been taken from another packet, so again
2759534696bSNeale Ranns   * constrained in  value */
2769534696bSNeale Ranns  ip4->tos |= dscp << IP_PACKET_TC_FIELD_DSCP_BIT_SHIFT;
2779534696bSNeale Ranns}
2789534696bSNeale Ranns
2799534696bSNeale Rannsalways_inline void
2809534696bSNeale Rannsip4_header_set_ecn (ip4_header_t * ip4, ip_ecn_t ecn)
2819534696bSNeale Ranns{
2829534696bSNeale Ranns  ip4->tos &= ~IP_PACKET_TC_FIELD_ECN_MASK;
2839534696bSNeale Ranns  ip4->tos |= ecn;
2849534696bSNeale Ranns}
2859534696bSNeale Ranns
2869534696bSNeale Rannsalways_inline void
2879534696bSNeale Rannsip4_header_set_ecn_w_chksum (ip4_header_t * ip4, ip_ecn_t ecn)
2889534696bSNeale Ranns{
2899534696bSNeale Ranns  ip_csum_t sum = ip4->checksum;
2909534696bSNeale Ranns  u8 old = ip4->tos;
2919534696bSNeale Ranns  u8 new = (old & ~IP_PACKET_TC_FIELD_ECN_MASK) | ecn;
2929534696bSNeale Ranns
2939534696bSNeale Ranns  sum = ip_csum_update (sum, old, new, ip4_header_t, tos);
2949534696bSNeale Ranns  ip4->checksum = ip_csum_fold (sum);
2959534696bSNeale Ranns  ip4->tos = new;
2969534696bSNeale Ranns}
2979534696bSNeale Ranns
2989534696bSNeale Rannsalways_inline ip_dscp_t
2999534696bSNeale Rannsip4_header_get_dscp (const ip4_header_t * ip4)
3009534696bSNeale Ranns{
3019534696bSNeale Ranns  return (ip4->tos >> IP_PACKET_TC_FIELD_DSCP_BIT_SHIFT);
3029534696bSNeale Ranns}
3039534696bSNeale Ranns
3049534696bSNeale Rannsalways_inline ip_ecn_t
3059534696bSNeale Rannsip4_header_get_ecn (const ip4_header_t * ip4)
3069534696bSNeale Ranns{
3079534696bSNeale Ranns  return (ip4->tos & IP_PACKET_TC_FIELD_ECN_MASK);
3089534696bSNeale Ranns}
3099534696bSNeale Ranns
3109534696bSNeale Rannsalways_inline void
3119534696bSNeale Rannsip4_header_set_df (ip4_header_t * ip4)
3129534696bSNeale Ranns{
3139534696bSNeale Ranns  ip4->flags_and_fragment_offset |=
3149534696bSNeale Ranns    clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT);
3159534696bSNeale Ranns}
3169534696bSNeale Ranns
3179534696bSNeale Rannsalways_inline void
3189534696bSNeale Rannsip4_header_clear_df (ip4_header_t * ip4)
3199534696bSNeale Ranns{
3209534696bSNeale Ranns  ip4->flags_and_fragment_offset &=
3219534696bSNeale Ranns    ~clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT);
3229534696bSNeale Ranns}
3239534696bSNeale Ranns
3249534696bSNeale Rannsalways_inline u8
325e5b94ddeSNeale Rannsip4_header_get_df (const ip4_header_t * ip4)
3269534696bSNeale Ranns{
3279534696bSNeale Ranns  return (! !(ip4->flags_and_fragment_offset &
3289534696bSNeale Ranns	      clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT)));
3299534696bSNeale Ranns}
3309534696bSNeale Ranns
331cb9cadadSEd Warnickestatic inline uword
332cb9cadadSEd Warnickeip4_header_checksum_is_valid (ip4_header_t * i)
333d7cb1b5fSDave Barach{
334d7cb1b5fSDave Barach  return i->checksum == ip4_header_checksum (i);
335d7cb1b5fSDave Barach}
336cb9cadadSEd Warnicke
337cb9cadadSEd Warnicke#define ip4_partial_header_checksum_x1(ip0,sum0)			\
338cb9cadadSEd Warnickedo {									\
339cb9cadadSEd Warnicke  if (BITS (ip_csum_t) > 32)						\
340cb9cadadSEd Warnicke    {									\
341cb9cadadSEd Warnicke      sum0 = ip0->checksum_data_64[0];					\
342cb9cadadSEd Warnicke      sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_64[1]);	\
343cb9cadadSEd Warnicke      sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_64_32[0]);	\
344cb9cadadSEd Warnicke    }									\
345cb9cadadSEd Warnicke  else									\
346cb9cadadSEd Warnicke    {									\
347cb9cadadSEd Warnicke      sum0 = ip0->checksum_data_32[0];					\
348cb9cadadSEd Warnicke      sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[1]);	\
349cb9cadadSEd Warnicke      sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[2]);	\
350cb9cadadSEd Warnicke      sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[3]);	\
351cb9cadadSEd Warnicke      sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[4]);	\
352cb9cadadSEd Warnicke    }									\
353cb9cadadSEd Warnicke} while (0)
354cb9cadadSEd Warnicke
355cb9cadadSEd Warnicke#define ip4_partial_header_checksum_x2(ip0,ip1,sum0,sum1)		\
356cb9cadadSEd Warnickedo {									\
357cb9cadadSEd Warnicke  if (BITS (ip_csum_t) > 32)						\
358cb9cadadSEd Warnicke    {									\
359cb9cadadSEd Warnicke      sum0 = ip0->checksum_data_64[0];					\
360cb9cadadSEd Warnicke      sum1 = ip1->checksum_data_64[0];					\
361cb9cadadSEd Warnicke      sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_64[1]);	\
362cb9cadadSEd Warnicke      sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_64[1]);	\
363cb9cadadSEd Warnicke      sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_64_32[0]);	\
364cb9cadadSEd Warnicke      sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_64_32[0]);	\
365cb9cadadSEd Warnicke    }									\
366cb9cadadSEd Warnicke  else									\
367cb9cadadSEd Warnicke    {									\
368cb9cadadSEd Warnicke      sum0 = ip0->checksum_data_32[0];					\
369cb9cadadSEd Warnicke      sum1 = ip1->checksum_data_32[0];					\
370cb9cadadSEd Warnicke      sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[1]);	\
371cb9cadadSEd Warnicke      sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_32[1]);	\
372cb9cadadSEd Warnicke      sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[2]);	\
373cb9cadadSEd Warnicke      sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_32[2]);	\
374cb9cadadSEd Warnicke      sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[3]);	\
375cb9cadadSEd Warnicke      sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_32[3]);	\
376cb9cadadSEd Warnicke      sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[4]);	\
377cb9cadadSEd Warnicke      sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_32[4]);	\
378cb9cadadSEd Warnicke    }									\
379cb9cadadSEd Warnicke} while (0)
380cb9cadadSEd Warnicke
381cb9cadadSEd Warnickealways_inline uword
382d69f4396SNeale Rannsip4_address_is_multicast (const ip4_address_t * a)
383d7cb1b5fSDave Barach{
384d7cb1b5fSDave Barach  return (a->data[0] & 0xf0) == 0xe0;
385d7cb1b5fSDave Barach}
386cb9cadadSEd Warnicke
387d724e4f4SNeale Rannsalways_inline uword
388d724e4f4SNeale Rannsip4_address_is_global_broadcast (const ip4_address_t * a)
389d724e4f4SNeale Ranns{
390d724e4f4SNeale Ranns  return (a->as_u32) == 0xffffffff;
391d724e4f4SNeale Ranns}
392d724e4f4SNeale Ranns
393cb9cadadSEd Warnickealways_inline void
394d7cb1b5fSDave Barachip4_multicast_address_set_for_group (ip4_address_t * a,
395d7cb1b5fSDave Barach				     ip_multicast_group_t g)
396cb9cadadSEd Warnicke{
3972c29d750SDamjan Marion  ASSERT ((u32) g < (1 << 28));
398cb9cadadSEd Warnicke  a->as_u32 = clib_host_to_net_u32 ((0xe << 28) + g);
399cb9cadadSEd Warnicke}
400cb9cadadSEd Warnicke
401cb9cadadSEd Warnickealways_inline void
402d69f4396SNeale Rannsip4_multicast_ethernet_address (u8 * ethernet_address,
403d69f4396SNeale Ranns				const ip4_address_t * a)
404c5b13600SEyal Bari{
405d69f4396SNeale Ranns  const u8 *d = a->as_u8;
406c5b13600SEyal Bari
407c5b13600SEyal Bari  ethernet_address[0] = 0x01;
408c5b13600SEyal Bari  ethernet_address[1] = 0x00;
409c5b13600SEyal Bari  ethernet_address[2] = 0x5e;
410c5b13600SEyal Bari  ethernet_address[3] = d[1] & 0x7f;
411c5b13600SEyal Bari  ethernet_address[4] = d[2];
412c5b13600SEyal Bari  ethernet_address[5] = d[3];
413c5b13600SEyal Bari}
414c5b13600SEyal Bari
415c5b13600SEyal Barialways_inline void
416cb9cadadSEd Warnickeip4_tcp_reply_x1 (ip4_header_t * ip0, tcp_header_t * tcp0)
417cb9cadadSEd Warnicke{
418cb9cadadSEd Warnicke  u32 src0, dst0;
419cb9cadadSEd Warnicke
420cb9cadadSEd Warnicke  src0 = ip0->src_address.data_u32;
421cb9cadadSEd Warnicke  dst0 = ip0->dst_address.data_u32;
422cb9cadadSEd Warnicke  ip0->src_address.data_u32 = dst0;
423cb9cadadSEd Warnicke  ip0->dst_address.data_u32 = src0;
424cb9cadadSEd Warnicke
42568b0fb0cSDave Barach  src0 = tcp0->src;
42668b0fb0cSDave Barach  dst0 = tcp0->dst;
42768b0fb0cSDave Barach  tcp0->src = dst0;
42868b0fb0cSDave Barach  tcp0->dst = src0;
429cb9cadadSEd Warnicke}
430cb9cadadSEd Warnicke
431cb9cadadSEd Warnickealways_inline void
432cb9cadadSEd Warnickeip4_tcp_reply_x2 (ip4_header_t * ip0, ip4_header_t * ip1,
433cb9cadadSEd Warnicke		  tcp_header_t * tcp0, tcp_header_t * tcp1)
434cb9cadadSEd Warnicke{
435cb9cadadSEd Warnicke  u32 src0, dst0, src1, dst1;
436cb9cadadSEd Warnicke
437cb9cadadSEd Warnicke  src0 = ip0->src_address.data_u32;
438cb9cadadSEd Warnicke  src1 = ip1->src_address.data_u32;
439cb9cadadSEd Warnicke  dst0 = ip0->dst_address.data_u32;
440cb9cadadSEd Warnicke  dst1 = ip1->dst_address.data_u32;
441cb9cadadSEd Warnicke  ip0->src_address.data_u32 = dst0;
442cb9cadadSEd Warnicke  ip1->src_address.data_u32 = dst1;
443cb9cadadSEd Warnicke  ip0->dst_address.data_u32 = src0;
444cb9cadadSEd Warnicke  ip1->dst_address.data_u32 = src1;
445cb9cadadSEd Warnicke
44668b0fb0cSDave Barach  src0 = tcp0->src;
44768b0fb0cSDave Barach  src1 = tcp1->src;
44868b0fb0cSDave Barach  dst0 = tcp0->dst;
44968b0fb0cSDave Barach  dst1 = tcp1->dst;
45068b0fb0cSDave Barach  tcp0->src = dst0;
45168b0fb0cSDave Barach  tcp1->src = dst1;
45268b0fb0cSDave Barach  tcp0->dst = src0;
45368b0fb0cSDave Barach  tcp1->dst = src1;
454cb9cadadSEd Warnicke}
455cb9cadadSEd Warnicke
456cb9cadadSEd Warnicke#endif /* included_ip4_packet_h */
457d7cb1b5fSDave Barach
458d7cb1b5fSDave Barach/*
459d7cb1b5fSDave Barach * fd.io coding-style-patch-verification: ON
460d7cb1b5fSDave Barach *
461d7cb1b5fSDave Barach * Local Variables:
462d7cb1b5fSDave Barach * eval: (c-set-style "gnu")
463d7cb1b5fSDave Barach * End:
464d7cb1b5fSDave Barach */