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

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

Find the association to deliver the datagram using amap.

  • Property mode set to 100644
File size: 9.2 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 memcpy(data_copy, packet->data, packet->size);
199
200 frag->packet = *packet;
201 frag->packet.data = data_copy;
202
203 /*
204 * XXX Make resource-consuming attacks harder, eliminate any duplicate
205 * data immediately. Possibly eliminate redundant packet headers.
206 */
207
208 /*
209 * Insert into the list, which is sorted by offs member ascending.
210 */
211
212 link = list_first(&rdg->frags);
213 while (link != NULL) {
214 reass_frag_t *qf = list_get_instance(link, reass_frag_t,
215 dgram_link);
216
217 if (qf->packet.offs >= packet->offs)
218 break;
219
220 link = list_next(link, &rdg->frags);
221 }
222
223 if (link != NULL)
224 list_insert_after(&frag->dgram_link, link);
225 else
226 list_append(&frag->dgram_link, &rdg->frags);
227
228 return EOK;
229}
230
231/** Check if datagram is complete.
232 *
233 * @param rdg Datagram reassembly structure
234 * @return @c true if complete, @c false if not
235 */
236static bool reass_dgram_complete(reass_dgram_t *rdg)
237{
238 reass_frag_t *frag, *prev;
239 link_t *link;
240
241 assert(fibril_mutex_is_locked(&reass_dgram_map_lock));
242 assert(!list_empty(&rdg->frags));
243
244 link = list_first(&rdg->frags);
245 assert(link != NULL);
246
247 frag = list_get_instance(link, reass_frag_t,
248 dgram_link);
249
250 /* First fragment must be at offset zero */
251 if (frag->packet.offs != 0)
252 return false;
253
254 prev = frag;
255
256 while (true) {
257 link = list_next(link, &rdg->frags);
258 if (link == NULL)
259 break;
260
261 /* Each next fragment must follow immediately or overlap */
262 frag = list_get_instance(link, reass_frag_t, dgram_link);
263 if (frag->packet.offs > prev->packet.offs + prev->packet.size)
264 return false;
265
266 /* No more fragments - datagram is complete */
267 if (!frag->packet.mf)
268 return true;
269
270 prev = frag;
271 }
272
273 return false;
274}
275
276/** Remove datagram from reassembly map.
277 *
278 * @param rdg Datagram reassembly structure
279 */
280static void reass_dgram_remove(reass_dgram_t *rdg)
281{
282 assert(fibril_mutex_is_locked(&reass_dgram_map_lock));
283 list_remove(&rdg->map_link);
284}
285
286/** Deliver complete datagram.
287 *
288 * @param rdg Datagram reassembly structure.
289 */
290static int reass_dgram_deliver(reass_dgram_t *rdg)
291{
292 size_t dgram_size;
293 size_t fragoff_limit;
294 inet_dgram_t dgram;
295 uint8_t proto;
296 reass_frag_t *frag;
297 int rc;
298
299 /*
300 * Potentially there could be something beyond the first packet
301 * that has !MF. Make sure we ignore that.
302 */
303 frag = NULL;
304 list_foreach(rdg->frags, dgram_link, reass_frag_t, cfrag) {
305 if (!cfrag->packet.mf) {
306 frag = cfrag;
307 break;
308 }
309 }
310
311 assert(frag != NULL);
312 assert(!frag->packet.mf);
313
314 dgram_size = frag->packet.offs + frag->packet.size;
315
316 /* Upper bound for fragment offset field */
317 fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l + 1);
318
319 /* Verify that total size of datagram is within reasonable bounds */
320 if (dgram_size > FRAG_OFFS_UNIT * fragoff_limit)
321 return ELIMIT;
322
323 dgram.data = calloc(dgram_size, 1);
324 if (dgram.data == NULL)
325 return ENOMEM;
326
327 /* XXX What if different fragments came from different link? */
328 dgram.iplink = frag->packet.link_id;
329 dgram.size = dgram_size;
330 dgram.src = frag->packet.src;
331 dgram.dest = frag->packet.dest;
332 dgram.tos = frag->packet.tos;
333 proto = frag->packet.proto;
334
335 /* Pull together data from individual fragments */
336
337 size_t doffs = 0;
338
339 list_foreach(rdg->frags, dgram_link, reass_frag_t, cfrag) {
340 size_t cb, ce;
341
342 cb = max(doffs, cfrag->packet.offs);
343 ce = min(dgram_size, cfrag->packet.offs + cfrag->packet.size);
344
345 if (ce > cb) {
346 memcpy(dgram.data + cb,
347 cfrag->packet.data + cb - cfrag->packet.offs,
348 ce - cb);
349 }
350
351 if (!cfrag->packet.mf)
352 break;
353 }
354
355 rc = inet_recv_dgram_local(&dgram, proto);
356 free(dgram.data);
357 return rc;
358}
359
360/** Destroy datagram reassembly structure.
361 *
362 * @param rdg Datagram reassembly structure.
363 */
364static void reass_dgram_destroy(reass_dgram_t *rdg)
365{
366 while (!list_empty(&rdg->frags)) {
367 link_t *flink = list_first(&rdg->frags);
368 reass_frag_t *frag = list_get_instance(flink, reass_frag_t,
369 dgram_link);
370
371 list_remove(&frag->dgram_link);
372 free(frag->packet.data);
373 free(frag);
374 }
375
376 free(rdg);
377}
378
379/** @}
380 */
Note: See TracBrowser for help on using the repository browser.