iPXE
Functions
fragment.c File Reference

Fragment reassembly. More...

#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <ipxe/retry.h>
#include <ipxe/timer.h>
#include <ipxe/ipstat.h>
#include <ipxe/fragment.h>

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
 
 FILE_SECBOOT (PERMITTED)
 
static void fragment_expired (struct retry_timer *timer, int fail __unused)
 Expire fragment reassembly buffer. More...
 
static struct fragmentfragment_find (struct fragment_reassembler *fragments, struct io_buffer *iobuf, size_t hdrlen)
 Find fragment reassembly buffer. More...
 
struct io_bufferfragment_reassemble (struct fragment_reassembler *fragments, struct io_buffer *iobuf, size_t *hdrlen)
 Reassemble packet. More...
 

Detailed Description

Fragment reassembly.

Definition in file fragment.c.

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )

◆ FILE_SECBOOT()

FILE_SECBOOT ( PERMITTED  )

◆ fragment_expired()

static void fragment_expired ( struct retry_timer timer,
int fail  __unused 
)
static

Expire fragment reassembly buffer.

Parameters
timerRetry timer
failFailure indicator

Definition at line 47 of file fragment.c.

47  {
48  struct fragment *fragment =
49  container_of ( timer, struct fragment, timer );
50 
51  DBGC ( fragment, "FRAG %p expired\n", fragment );
52  free_iob ( fragment->iobuf );
53  list_del ( &fragment->list );
55  free ( fragment );
56 }
struct list_head list
Definition: fragment.h:24
struct ip_statistics * stats
Associated IP statistics.
Definition: fragment.h:66
A fragment reassembly buffer.
Definition: fragment.h:22
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition: iobuf.c:153
#define DBGC(...)
Definition: compiler.h:505
A timer.
Definition: timer.h:29
#define list_del(list)
Delete an entry from a list.
Definition: list.h:120
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:36
unsigned long reasm_fails
ipSystemStatsReasmFails
Definition: ipstat.h:111
struct io_buffer * iobuf
Reassembled packet.
Definition: fragment.h:26
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:55
struct fragment_reassembler * fragments
Fragment reassembler.
Definition: fragment.h:32

References container_of, DBGC, fragment::fragments, free, free_iob(), fragment::iobuf, fragment::list, list_del, ip_statistics::reasm_fails, and fragment_reassembler::stats.

Referenced by fragment_reassemble().

◆ fragment_find()

static struct fragment* fragment_find ( struct fragment_reassembler fragments,
struct io_buffer iobuf,
size_t  hdrlen 
)
static

Find fragment reassembly buffer.

Parameters
fragmentsFragment reassembler
iobufI/O buffer
hdrlenLength of non-fragmentable potion of I/O buffer
Return values
fragmentFragment reassembly buffer, or NULL if not found

Definition at line 66 of file fragment.c.

68  {
69  struct fragment *fragment;
70 
73  return fragment;
74  }
75  return NULL;
76 }
struct list_head list
Definition: fragment.h:24
A fragment reassembly buffer.
Definition: fragment.h:22
#define list_for_each_entry(pos, head, member)
Iterate over entries in a list.
Definition: list.h:432
struct io_buffer * iobuf
Reassembled packet.
Definition: fragment.h:26
struct fragment_reassembler * fragments
Fragment reassembler.
Definition: fragment.h:32
int(* is_fragment)(struct fragment *fragment, struct io_buffer *iobuf, size_t hdrlen)
Check if fragment matches fragment reassembly buffer.
Definition: fragment.h:47
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
struct list_head list
List of fragment reassembly buffers.
Definition: fragment.h:38
size_t hdrlen
Length of non-fragmentable portion of reassembled packet.
Definition: fragment.h:28

References fragment::fragments, fragment::hdrlen, fragment::iobuf, fragment_reassembler::is_fragment, fragment_reassembler::list, fragment::list, list_for_each_entry, and NULL.

Referenced by fragment_reassemble().

◆ fragment_reassemble()

struct io_buffer* fragment_reassemble ( struct fragment_reassembler fragments,
struct io_buffer iobuf,
size_t hdrlen 
)

Reassemble packet.

Parameters
fragmentsFragment reassembler
iobufI/O buffer
hdrlenLength of non-fragmentable potion of I/O buffer
Return values
iobufReassembled packet, or NULL

This function takes ownership of the I/O buffer. Note that the length of the non-fragmentable portion may be modified.

Definition at line 89 of file fragment.c.

91  {
92  struct fragment *fragment;
93  struct io_buffer *new_iobuf;
94  size_t new_len;
95  size_t offset;
96  size_t expected_offset;
97  int more_frags;
98 
99  /* Update statistics */
100  fragments->stats->reasm_reqds++;
101 
102  /* Find matching fragment reassembly buffer, if any */
103  fragment = fragment_find ( fragments, iobuf, *hdrlen );
104 
105  /* Drop out-of-order fragments */
106  offset = fragments->fragment_offset ( iobuf, *hdrlen );
107  expected_offset = ( fragment ? ( iob_len ( fragment->iobuf ) -
108  fragment->hdrlen ) : 0 );
109  if ( offset != expected_offset ) {
110  DBGC ( fragment, "FRAG %p dropping out-of-sequence fragment "
111  "[%zd,%zd), expected [%zd,...)\n", fragment, offset,
112  ( offset + iob_len ( iobuf ) - *hdrlen ),
113  expected_offset );
114  goto drop;
115  }
116 
117  /* Create or extend fragment reassembly buffer as applicable */
118  if ( ! fragment ) {
119 
120  /* Create new fragment reassembly buffer */
121  fragment = zalloc ( sizeof ( *fragment ) );
122  if ( ! fragment )
123  goto drop;
124  list_add ( &fragment->list, &fragments->list );
125  fragment->iobuf = iobuf;
126  fragment->hdrlen = *hdrlen;
127  timer_init ( &fragment->timer, fragment_expired, NULL );
128  fragment->fragments = fragments;
129  DBGC ( fragment, "FRAG %p [0,%zd)\n", fragment,
130  ( iob_len ( iobuf ) - *hdrlen ) );
131 
132  } else {
133 
134  /* Check if this is the final fragment */
135  more_frags = fragments->more_fragments ( iobuf, *hdrlen );
136  DBGC ( fragment, "FRAG %p [%zd,%zd)%s\n", fragment,
137  offset, ( offset + iob_len ( iobuf ) - *hdrlen ),
138  ( more_frags ? "" : " complete" ) );
139 
140  /* Extend fragment reassembly buffer. Preserve I/O
141  * buffer headroom to allow for code which modifies
142  * and resends the buffer (e.g. ICMP echo responses).
143  */
144  iob_pull ( iobuf, *hdrlen );
145  new_len = ( iob_headroom ( fragment->iobuf ) +
146  iob_len ( fragment->iobuf ) + iob_len ( iobuf ) );
147  new_iobuf = alloc_iob ( new_len );
148  if ( ! new_iobuf ) {
149  DBGC ( fragment, "FRAG %p could not extend reassembly "
150  "buffer to %zd bytes\n", fragment, new_len );
151  goto drop;
152  }
153  iob_reserve ( new_iobuf, iob_headroom ( fragment->iobuf ) );
154  memcpy ( iob_put ( new_iobuf, iob_len ( fragment->iobuf ) ),
156  memcpy ( iob_put ( new_iobuf, iob_len ( iobuf ) ),
157  iobuf->data, iob_len ( iobuf ) );
158  free_iob ( fragment->iobuf );
159  fragment->iobuf = new_iobuf;
160  free_iob ( iobuf );
161 
162  /* Stop fragment reassembly timer */
163  stop_timer ( &fragment->timer );
164 
165  /* If this is the final fragment, return it */
166  if ( ! more_frags ) {
167  iobuf = fragment->iobuf;
168  *hdrlen = fragment->hdrlen;
169  list_del ( &fragment->list );
170  free ( fragment );
171  fragments->stats->reasm_oks++;
172  return iobuf;
173  }
174  }
175 
176  /* (Re)start fragment reassembly timer */
178 
179  return NULL;
180 
181  drop:
182  fragments->stats->reasm_fails++;
183  free_iob ( iobuf );
184  return NULL;
185 }
struct list_head list
Definition: fragment.h:24
unsigned long reasm_reqds
ipSystemStatsReasmReqds
Definition: ipstat.h:96
#define iob_pull(iobuf, len)
Definition: iobuf.h:107
unsigned long reasm_oks
ipSystemStatsReasmOks
Definition: ipstat.h:101
#define iob_put(iobuf, len)
Definition: iobuf.h:125
struct ip_statistics * stats
Associated IP statistics.
Definition: fragment.h:66
static struct fragment * fragment_find(struct fragment_reassembler *fragments, struct io_buffer *iobuf, size_t hdrlen)
Find fragment reassembly buffer.
Definition: fragment.c:66
#define list_add(new, head)
Add a new entry to the head of a list.
Definition: list.h:70
A fragment reassembly buffer.
Definition: fragment.h:22
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition: iobuf.c:153
#define DBGC(...)
Definition: compiler.h:505
struct io_buffer * alloc_iob(size_t len)
Allocate I/O buffer.
Definition: iobuf.c:131
#define list_del(list)
Delete an entry from a list.
Definition: list.h:120
void * memcpy(void *dest, const void *src, size_t len) __nonnull
unsigned long reasm_fails
ipSystemStatsReasmFails
Definition: ipstat.h:111
struct io_buffer * iobuf
Reassembled packet.
Definition: fragment.h:26
size_t(* fragment_offset)(struct io_buffer *iobuf, size_t hdrlen)
Get fragment offset.
Definition: fragment.h:56
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:55
void * zalloc(size_t size)
Allocate cleared memory.
Definition: malloc.c:662
static void fragment_expired(struct retry_timer *timer, int fail __unused)
Expire fragment reassembly buffer.
Definition: fragment.c:47
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:160
struct fragment_reassembler * fragments
Fragment reassembler.
Definition: fragment.h:32
void start_timer_fixed(struct retry_timer *timer, unsigned long timeout)
Start timer with a specified timeout.
Definition: retry.c:65
#define iob_reserve(iobuf, len)
Definition: iobuf.h:72
void stop_timer(struct retry_timer *timer)
Stop timer.
Definition: retry.c:118
static size_t iob_headroom(struct io_buffer *iobuf)
Calculate available space at start of an I/O buffer.
Definition: iobuf.h:170
int(* more_fragments)(struct io_buffer *iobuf, size_t hdrlen)
Check if more fragments exist.
Definition: fragment.h:64
void * data
Start of data.
Definition: iobuf.h:53
struct retry_timer timer
Reassembly timer.
Definition: fragment.h:30
#define FRAGMENT_TIMEOUT
Fragment reassembly timeout.
Definition: fragment.h:19
uint16_t offset
Offset to command line.
Definition: bzimage.h:8
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
struct list_head list
List of fragment reassembly buffers.
Definition: fragment.h:38
A persistent I/O buffer.
Definition: iobuf.h:38
size_t hdrlen
Length of non-fragmentable portion of reassembled packet.
Definition: fragment.h:28

References alloc_iob(), io_buffer::data, DBGC, fragment_expired(), fragment_find(), fragment_reassembler::fragment_offset, FRAGMENT_TIMEOUT, fragment::fragments, free, free_iob(), fragment::hdrlen, iob_headroom(), iob_len(), iob_pull, iob_put, iob_reserve, fragment::iobuf, fragment_reassembler::list, fragment::list, list_add, list_del, memcpy(), fragment_reassembler::more_fragments, NULL, offset, ip_statistics::reasm_fails, ip_statistics::reasm_oks, ip_statistics::reasm_reqds, start_timer_fixed(), fragment_reassembler::stats, stop_timer(), fragment::timer, and zalloc().

Referenced by ipv4_rx(), and ipv6_rx().