API Reference Manual  1.46.0
odp_ipfragreass_fragment.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2017-2018 Linaro Limited
3  */
4 
7 #include <stdio.h>
8 #include <assert.h>
9 
10 #include "odp_ipfragreass_ip.h"
11 #include "odp_ipfragreass_fragment.h"
12 
13 int fragment_ipv4_packet(odp_packet_t orig_packet, odp_packet_t *out,
14  int *out_len)
15 {
16  int fragments = 0;
17  odp_bool_t first_fragment = 1;
18  odph_ipv4hdr_t *orig_header = odp_packet_data(orig_packet);
19  uint32_t header_len = ipv4hdr_ihl(*orig_header);
20  uint32_t orig_len = odp_packet_len(orig_packet);
21  uint32_t bytes_remaining = orig_len - header_len;
22  uint32_t frag_offset = 0;
23  odp_packet_t frag = orig_packet;
25 
26  if (bytes_remaining <= MTU)
27  return -1;
28 
29  /*
30  * The main fragmentation loop (continue until all bytes from the
31  * original payload have been assigned to a fragment)
32  */
33  while (bytes_remaining) {
34  odph_ipv4hdr_t *header;
35  uint32_t frag_len;
36 
37  frag_len = (bytes_remaining > MTU ? (MTU + header_len)
38  : (bytes_remaining
39  + header_len));
40  bytes_remaining -= (frag_len - header_len);
41  if (bytes_remaining) {
42  uint32_t split_point;
43  int split_success;
44 
45  split_point = first_fragment ? (frag_len)
46  : (frag_len - header_len);
47  split_success = odp_packet_split(&frag, split_point,
48  &rest);
49  if (split_success < 0) {
50  fprintf(stderr,
51  "ERROR: odp_packet_split\n");
52  return -1;
53  } else if (first_fragment && split_success > 0) {
54  orig_header = odp_packet_data(frag);
55  }
56  }
57 
58  /* Add a header to the packet if necessary */
59  if (first_fragment) {
60  first_fragment = 0;
61  } else {
62  if (odp_packet_extend_head(&frag, header_len, NULL,
63  NULL) < 0) {
64  fprintf(stderr,
65  "ERROR: odp_packet_extend_head\n");
66  return -1;
67  }
68  if (odp_packet_copy_from_mem(frag, 0, header_len,
69  orig_header)) {
70  fprintf(stderr,
71  "ERROR: odp_packet_copy_from_mem\n");
72  return -1;
73  }
74  }
75 
76  /* Update the header */
77  header = odp_packet_data(frag);
78  ipv4hdr_set_more_fragments(header, bytes_remaining != 0);
79  header->tot_len = odp_cpu_to_be_16(frag_len);
80  ipv4hdr_set_fragment_offset_oct(header, (frag_offset / 8));
81  assert((bytes_remaining == 0) ||
82  (odp_packet_len(frag) == (MTU + header_len)));
83  assert((bytes_remaining != 0) ||
84  (ipv4hdr_reass_payload_len(*header) + header_len
85  == orig_len));
86  odp_packet_l3_offset_set(frag, 0);
87  header->chksum = 0;
88  odph_ipv4_csum_update(frag);
89 
90  out[fragments++] = frag;
91  frag = rest;
92  frag_offset += (frag_len - header_len);
93  }
94 
95  if (out_len)
96  *out_len = fragments;
97 
98  return 0;
99 }
odp_u16be_t odp_cpu_to_be_16(uint16_t cpu16)
Convert cpu native uint16_t to 16bit big endian.
int odp_packet_l3_offset_set(odp_packet_t pkt, uint32_t offset)
Set layer 3 start offset.
void * odp_packet_data(odp_packet_t pkt)
Packet data pointer.
int odp_packet_extend_head(odp_packet_t *pkt, uint32_t len, void **data_ptr, uint32_t *seg_len)
Extend packet head.
int odp_packet_split(odp_packet_t *pkt, uint32_t len, odp_packet_t *tail)
Split packet into two packets.
uint32_t odp_packet_len(odp_packet_t pkt)
Packet data length.
int odp_packet_copy_from_mem(odp_packet_t pkt, uint32_t offset, uint32_t len, const void *src)
Copy data from memory to packet.
#define ODP_PACKET_INVALID
Invalid packet.
bool odp_bool_t
Boolean type.