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)
 
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  )

◆ 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 46 of file fragment.c.

46  {
47  struct fragment *fragment =
48  container_of ( timer, struct fragment, timer );
49 
50  DBGC ( fragment, "FRAG %p expired\n", fragment );
51  free_iob ( fragment->iobuf );
52  list_del ( &fragment->list );
54  free ( fragment );
55 }
struct list_head list
Definition: fragment.h:23
struct ip_statistics * stats
Associated IP statistics.
Definition: fragment.h:65
A fragment reassembly buffer.
Definition: fragment.h:21
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition: iobuf.c:146
#define DBGC(...)
Definition: compiler.h:505
A timer.
Definition: timer.h:28
#define list_del(list)
Delete an entry from a list.
Definition: list.h:119
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:35
unsigned long reasm_fails
ipSystemStatsReasmFails
Definition: ipstat.h:110
struct io_buffer * iobuf
Reassembled packet.
Definition: fragment.h:25
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
struct fragment_reassembler * fragments
Fragment reassembler.
Definition: fragment.h:31

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 65 of file fragment.c.

67  {
68  struct fragment *fragment;
69 
72  return fragment;
73  }
74  return NULL;
75 }
struct list_head list
Definition: fragment.h:23
A fragment reassembly buffer.
Definition: fragment.h:21
#define list_for_each_entry(pos, head, member)
Iterate over entries in a list.
Definition: list.h:431
struct io_buffer * iobuf
Reassembled packet.
Definition: fragment.h:25
struct fragment_reassembler * fragments
Fragment reassembler.
Definition: fragment.h:31
int(* is_fragment)(struct fragment *fragment, struct io_buffer *iobuf, size_t hdrlen)
Check if fragment matches fragment reassembly buffer.
Definition: fragment.h:46
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
struct list_head list
List of fragment reassembly buffers.
Definition: fragment.h:37
size_t hdrlen
Length of non-fragmentable portion of reassembled packet.
Definition: fragment.h:27

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 88 of file fragment.c.

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

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().