iPXE
fragment.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27#include <stdint.h>
28#include <stdlib.h>
29#include <string.h>
30#include <ipxe/retry.h>
31#include <ipxe/timer.h>
32#include <ipxe/ipstat.h>
33#include <ipxe/fragment.h>
34
35/** @file
36 *
37 * Fragment reassembly
38 *
39 */
40
41/**
42 * Expire fragment reassembly buffer
43 *
44 * @v timer Retry timer
45 * @v fail Failure indicator
46 */
47static void fragment_expired ( struct retry_timer *timer, int fail __unused ) {
48 struct fragment *fragment =
49 container_of ( timer, struct fragment, timer );
50
51 DBGC ( fragment, "FRAG %p expired\n", fragment );
55 free ( fragment );
56}
57
58/**
59 * Find fragment reassembly buffer
60 *
61 * @v fragments Fragment reassembler
62 * @v iobuf I/O buffer
63 * @v hdrlen Length of non-fragmentable potion of I/O buffer
64 * @ret fragment Fragment reassembly buffer, or NULL if not found
65 */
67 struct io_buffer *iobuf,
68 size_t hdrlen ) {
69 struct fragment *fragment;
70
73 return fragment;
74 }
75 return NULL;
76}
77
78/**
79 * Reassemble packet
80 *
81 * @v fragments Fragment reassembler
82 * @v iobuf I/O buffer
83 * @v hdrlen Length of non-fragmentable potion of I/O buffer
84 * @ret iobuf Reassembled packet, or NULL
85 *
86 * This function takes ownership of the I/O buffer. Note that the
87 * length of the non-fragmentable portion may be modified.
88 */
90 struct io_buffer *iobuf,
91 size_t *hdrlen ) {
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}
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
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
struct io_buffer * fragment_reassemble(struct fragment_reassembler *fragments, struct io_buffer *iobuf, size_t *hdrlen)
Reassemble packet.
Definition fragment.c:89
static struct fragment * fragment_find(struct fragment_reassembler *fragments, struct io_buffer *iobuf, size_t hdrlen)
Find fragment reassembly buffer.
Definition fragment.c:66
Fragment reassembly.
#define FRAGMENT_TIMEOUT
Fragment reassembly timeout.
Definition fragment.h:19
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:573
#define DBGC(...)
Definition compiler.h:505
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
iPXE timers
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition iobuf.c:153
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
IP statistics.
#define list_for_each_entry(pos, head, member)
Iterate over entries in a list.
Definition list.h:432
#define list_del(list)
Delete an entry from a list.
Definition list.h:120
#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
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
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
Retry timers.
#define container_of(ptr, type, field)
Get containing structure.
Definition stddef.h:36
A fragment reassembler.
Definition fragment.h:36
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(* fragment_offset)(struct io_buffer *iobuf, size_t hdrlen)
Get fragment offset.
Definition fragment.h:56
struct ip_statistics * stats
Associated IP statistics.
Definition fragment.h:66
int(* more_fragments)(struct io_buffer *iobuf, size_t hdrlen)
Check if more fragments exist.
Definition fragment.h:64
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
size_t hdrlen
Length of non-fragmentable portion of reassembled packet.
Definition fragment.h:28
struct fragment_reassembler * fragments
Fragment reassembler.
Definition fragment.h:32
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
unsigned long reasm_fails
ipSystemStatsReasmFails
Definition ipstat.h:111
A retry timer.
Definition retry.h:22
A timer.
Definition timer.h:29