source: mainline/uspace/srv/net/inetsrv/reass.c@ b8b1adb1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b8b1adb1 was feeac0d, checked in by Jiri Svoboda <jiri@…>, 12 years ago

Simplify use of list_foreach.

  • Property mode set to 100644
File size: 8.9 KB
Line 
1/*
2 * Copyright (c) 2012 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup inet
30 * @{
31 */
32/**
33 * @file
34 * @brief Datagram reassembly.
35 */
36
37#include <errno.h>
38#include <fibril_synch.h>
39#include <io/log.h>
40#include <macros.h>
41#include <mem.h>
42#include <stdlib.h>
43
44#include "inetsrv.h"
45#include "inet_std.h"
46#include "reass.h"
47
48/** Datagram being reassembled.
49 *
50 * Uniquely identified by (source address, destination address, protocol,
51 * identification) per RFC 791 sec. 2.3 / Fragmentation.
52 */
53typedef struct {
54 link_t map_link;
55 /** List of fragments, @c reass_frag_t */
56 list_t frags;
57} reass_dgram_t;
58
59/** One datagram fragment */
60typedef struct {
61 link_t dgram_link;
62 inet_packet_t packet;
63} reass_frag_t;
64
65/** Datagram map, list of reass_dgram_t */
66static LIST_INITIALIZE(reass_dgram_map);
67/** Protects access to @c reass_dgram_map */
68static FIBRIL_MUTEX_INITIALIZE(reass_dgram_map_lock);
69
70static reass_dgram_t *reass_dgram_new(void);
71static reass_dgram_t *reass_dgram_get(inet_packet_t *);
72static int reass_dgram_insert_frag(reass_dgram_t *, inet_packet_t *);
73static bool reass_dgram_complete(reass_dgram_t *);
74static void reass_dgram_remove(reass_dgram_t *);
75static int reass_dgram_deliver(reass_dgram_t *);
76static void reass_dgram_destroy(reass_dgram_t *);
77
78/** Queue packet for datagram reassembly.
79 *
80 * @param packet Packet
81 * @return EOK on success or ENOMEM.
82 */
83int inet_reass_queue_packet(inet_packet_t *packet)
84{
85 reass_dgram_t *rdg;
86 int rc;
87
88 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_reass_queue_packet()");
89
90 fibril_mutex_lock(&reass_dgram_map_lock);
91
92 /* Get existing or new datagram */
93 rdg = reass_dgram_get(packet);
94 if (rdg == NULL) {
95 /* Only happens when we are out of memory */
96 fibril_mutex_unlock(&reass_dgram_map_lock);
97 log_msg(LOG_DEFAULT, LVL_DEBUG, "Allocation failed, packet dropped.");
98 return ENOMEM;
99 }
100
101 /* Insert fragment into the datagram */
102 rc = reass_dgram_insert_frag(rdg, packet);
103 if (rc != EOK)
104 return ENOMEM;
105
106 /* Check if datagram is complete */
107 if (reass_dgram_complete(rdg)) {
108 /* Remove it from the map */
109 reass_dgram_remove(rdg);
110 fibril_mutex_unlock(&reass_dgram_map_lock);
111
112 /* Deliver complete datagram */
113 rc = reass_dgram_deliver(rdg);
114 reass_dgram_destroy(rdg);
115 return rc;
116 }
117
118 fibril_mutex_unlock(&reass_dgram_map_lock);
119 return EOK;
120}
121
122/** Get datagram reassembly structure for packet.
123 *
124 * @param packet Packet
125 * @return Datagram reassembly structure matching @a packet
126 */
127static reass_dgram_t *reass_dgram_get(inet_packet_t *packet)
128{
129 assert(fibril_mutex_is_locked(&reass_dgram_map_lock));
130
131 list_foreach(reass_dgram_map, map_link, reass_dgram_t, rdg) {
132 link_t *f1_link = list_first(&rdg->frags);
133 assert(f1_link != NULL);
134
135 reass_frag_t *f1 = list_get_instance(f1_link, reass_frag_t,
136 dgram_link);
137
138 if ((inet_addr_compare(&f1->packet.src, &packet->src)) &&
139 (inet_addr_compare(&f1->packet.dest, &packet->dest)) &&
140 (f1->packet.proto == packet->proto) &&
141 (f1->packet.ident == packet->ident)) {
142 /* Match */
143 return rdg;
144 }
145 }
146
147 /* No existing reassembly structure. Create a new one. */
148 return reass_dgram_new();
149}
150
151/** Create new datagram reassembly structure.
152 *
153 * @return New datagram reassembly structure.
154 */
155static reass_dgram_t *reass_dgram_new(void)
156{
157 reass_dgram_t *rdg;
158
159 rdg = calloc(1, sizeof(reass_dgram_t));
160 if (rdg == NULL)
161 return NULL;
162
163 list_append(&rdg->map_link, &reass_dgram_map);
164 list_initialize(&rdg->frags);
165
166 return rdg;
167}
168
169static reass_frag_t *reass_frag_new(void)
170{
171 reass_frag_t *frag;
172
173 frag = calloc(1, sizeof(reass_frag_t));
174 if (frag == NULL)
175 return NULL;
176
177 link_initialize(&frag->dgram_link);
178
179 return frag;
180}
181
182static int reass_dgram_insert_frag(reass_dgram_t *rdg, inet_packet_t *packet)
183{
184 reass_frag_t *frag;
185 void *data_copy;
186 link_t *link;
187
188 assert(fibril_mutex_is_locked(&reass_dgram_map_lock));
189
190 frag = reass_frag_new();
191
192 /* Clone the packet */
193
194 data_copy = malloc(packet->size);
195 if (data_copy == NULL)
196 return ENOMEM;
197
198 frag->packet = *packet;
199 frag->packet.data = data_copy;
200
201 /*
202 * XXX Make resource-consuming attacks harder, eliminate any duplicate
203 * data immediately. Possibly eliminate redundant packet headers.
204 */
205
206 /*
207 * Insert into the list, which is sorted by offs member ascending.
208 */
209
210 link = list_first(&rdg->frags);
211 while (link != NULL) {
212 reass_frag_t *qf = list_get_instance(link, reass_frag_t,
213 dgram_link);
214
215 if (qf->packet.offs >= packet->offs)
216 break;
217
218 link = link->next;
219 }
220
221 if (link != NULL)
222 list_insert_after(&frag->dgram_link, link);
223 else
224 list_append(&frag->dgram_link, &rdg->frags);
225
226 return EOK;
227}
228
229/** Check if datagram is complete.
230 *
231 * @param rdg Datagram reassembly structure
232 * @return @c true if complete, @c false if not
233 */
234static bool reass_dgram_complete(reass_dgram_t *rdg)
235{
236 reass_frag_t *frag, *prev;
237 link_t *link;
238
239 assert(fibril_mutex_is_locked(&reass_dgram_map_lock));
240 assert(!list_empty(&rdg->frags));
241
242 /* First fragment must be at offset zero */
243 frag = list_get_instance(list_first(&rdg->frags), reass_frag_t,
244 dgram_link);
245 if (frag->packet.offs != 0)
246 return false;
247
248 prev = frag;
249 while (true) {
250 link = frag->dgram_link.next;
251 if (link == NULL)
252 return false;
253
254 /* Each next fragment must follow immediately or overlap */
255 frag = list_get_instance(link, reass_frag_t, dgram_link);
256 if (frag->packet.offs > prev->packet.offs + prev->packet.size)
257 return false;
258
259 /* No more fragments - datagram is complete */
260 if (!frag->packet.mf)
261 return true;
262
263 prev = frag;
264 }
265
266 return false;
267}
268
269/** Remove datagram from reassembly map.
270 *
271 * @param rdg Datagram reassembly structure
272 */
273static void reass_dgram_remove(reass_dgram_t *rdg)
274{
275 assert(fibril_mutex_is_locked(&reass_dgram_map_lock));
276 list_remove(&rdg->map_link);
277}
278
279/** Deliver complete datagram.
280 *
281 * @param rdg Datagram reassembly structure.
282 */
283static int reass_dgram_deliver(reass_dgram_t *rdg)
284{
285 size_t dgram_size;
286 size_t fragoff_limit;
287 inet_dgram_t dgram;
288 uint8_t proto;
289 reass_frag_t *frag;
290
291 /*
292 * Potentially there could be something beyond the first packet
293 * that has !MF. Make sure we ignore that.
294 */
295 frag = NULL;
296 list_foreach(rdg->frags, dgram_link, reass_frag_t, cfrag) {
297 if (!cfrag->packet.mf) {
298 frag = cfrag;
299 break;
300 }
301 }
302
303 assert(frag != NULL);
304 assert(!frag->packet.mf);
305
306 dgram_size = frag->packet.offs + frag->packet.size;
307
308 /* Upper bound for fragment offset field */
309 fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l);
310
311 /* Verify that total size of datagram is within reasonable bounds */
312 if (dgram_size > FRAG_OFFS_UNIT * fragoff_limit)
313 return ELIMIT;
314
315 dgram.data = calloc(dgram_size, 1);
316 if (dgram.data == NULL)
317 return ENOMEM;
318
319 dgram.size = dgram_size;
320 dgram.src = frag->packet.src;
321 dgram.dest = frag->packet.dest;
322 dgram.tos = frag->packet.tos;
323 proto = frag->packet.proto;
324
325 /* Pull together data from individual fragments */
326
327 size_t doffs = 0;
328
329 list_foreach(rdg->frags, dgram_link, reass_frag_t, cfrag) {
330 size_t cb, ce;
331
332 cb = max(doffs, cfrag->packet.offs);
333 ce = min(dgram_size, cfrag->packet.offs + cfrag->packet.size);
334
335 if (ce > cb) {
336 memcpy(dgram.data + cb,
337 cfrag->packet.data + cb - cfrag->packet.offs,
338 ce - cb);
339 }
340
341 if (!cfrag->packet.mf)
342 break;
343 }
344
345 return inet_recv_dgram_local(&dgram, proto);
346}
347
348/** Destroy datagram reassembly structure.
349 *
350 * @param rdg Datagram reassembly structure.
351 */
352static void reass_dgram_destroy(reass_dgram_t *rdg)
353{
354 while (!list_empty(&rdg->frags)) {
355 link_t *flink = list_first(&rdg->frags);
356 reass_frag_t *frag = list_get_instance(flink, reass_frag_t,
357 dgram_link);
358
359 list_remove(&frag->dgram_link);
360 free(frag->packet.data);
361 free(frag);
362 }
363
364 free(rdg);
365}
366
367/** @}
368 */
Note: See TracBrowser for help on using the repository browser.