iPXE
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.
static struct fragmentfragment_find (struct fragment_reassembler *fragments, struct io_buffer *iobuf, size_t hdrlen)
 Find fragment reassembly buffer.
struct io_bufferfragment_reassemble (struct fragment_reassembler *fragments, struct io_buffer *iobuf, size_t *hdrlen)
 Reassemble packet.

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

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 );
55 free ( fragment );
56}
#define DBGC(...)
Definition compiler.h:505
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition iobuf.c:153
#define list_del(list)
Delete an entry from a list.
Definition list.h:120
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
#define container_of(ptr, type, field)
Get containing structure.
Definition stddef.h:36
struct ip_statistics * stats
Associated IP statistics.
Definition fragment.h:66
A fragment reassembly buffer.
Definition fragment.h:22
struct io_buffer * iobuf
Reassembled packet.
Definition fragment.h:26
struct list_head list
Definition fragment.h:24
struct fragment_reassembler * fragments
Fragment reassembler.
Definition fragment.h:32
unsigned long reasm_fails
ipSystemStatsReasmFails
Definition ipstat.h:111
A timer.
Definition timer.h:29

References __unused, 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()

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}
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
#define list_for_each_entry(pos, head, member)
Iterate over entries in a list.
Definition list.h:432
struct list_head list
List of fragment reassembly buffers.
Definition fragment.h:38
int(* is_fragment)(struct fragment *fragment, struct io_buffer *iobuf, size_t hdrlen)
Check if fragment matches fragment reassembly buffer.
Definition fragment.h:47
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::list, fragment_reassembler::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 ) );
159 fragment->iobuf = new_iobuf;
160 free_iob ( iobuf );
161
162 /* Stop fragment reassembly 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}
uint16_t offset
Offset to command line.
Definition bzimage.h:3
static void fragment_expired(struct retry_timer *timer, int fail __unused)
Expire fragment reassembly buffer.
Definition fragment.c:47
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 FRAGMENT_TIMEOUT
Fragment reassembly timeout.
Definition fragment.h:19
void * memcpy(void *dest, const void *src, size_t len) __nonnull
struct io_buffer * alloc_iob(size_t len)
Allocate I/O buffer.
Definition iobuf.c:131
static size_t iob_headroom(struct io_buffer *iobuf)
Calculate available space at start of an I/O buffer.
Definition iobuf.h:170
#define iob_put(iobuf, len)
Definition iobuf.h:125
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:160
#define iob_reserve(iobuf, len)
Definition iobuf.h:72
#define iob_pull(iobuf, len)
Definition iobuf.h:107
#define list_add(new, head)
Add a new entry to the head of a list.
Definition list.h:70
void * zalloc(size_t size)
Allocate cleared memory.
Definition malloc.c:662
void start_timer_fixed(struct retry_timer *timer, unsigned long timeout)
Start timer with a specified timeout.
Definition retry.c:65
void stop_timer(struct retry_timer *timer)
Stop timer.
Definition retry.c:118
size_t(* fragment_offset)(struct io_buffer *iobuf, size_t hdrlen)
Get fragment offset.
Definition fragment.h:56
int(* more_fragments)(struct io_buffer *iobuf, size_t hdrlen)
Check if more fragments exist.
Definition fragment.h:64
struct retry_timer timer
Reassembly timer.
Definition fragment.h:30
A persistent I/O buffer.
Definition iobuf.h:38
void * data
Start of data.
Definition iobuf.h:53
unsigned long reasm_reqds
ipSystemStatsReasmReqds
Definition ipstat.h:96
unsigned long reasm_oks
ipSystemStatsReasmOks
Definition ipstat.h:101

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::list, fragment_reassembler::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().