HelenOS sources
This source file includes following definitions.
- inet_reass_queue_packet
- reass_dgram_get
- reass_dgram_new
- reass_frag_new
- reass_dgram_insert_frag
- reass_dgram_complete
- reass_dgram_remove
- reass_dgram_deliver
- reass_dgram_destroy
#include <errno.h>
#include <fibril_synch.h>
#include <io/log.h>
#include <macros.h>
#include <mem.h>
#include <stdlib.h>
#include "inetsrv.h"
#include "inet_std.h"
#include "reass.h"
typedef struct {
link_t map_link;
list_t frags;
} reass_dgram_t;
typedef struct {
link_t dgram_link;
inet_packet_t packet;
} reass_frag_t;
static LIST_INITIALIZE(reass_dgram_map);
static FIBRIL_MUTEX_INITIALIZE(reass_dgram_map_lock);
static reass_dgram_t *reass_dgram_new(void);
static reass_dgram_t *reass_dgram_get(inet_packet_t *);
static errno_t reass_dgram_insert_frag(reass_dgram_t *, inet_packet_t *);
static bool reass_dgram_complete(reass_dgram_t *);
static void reass_dgram_remove(reass_dgram_t *);
static errno_t reass_dgram_deliver(reass_dgram_t *);
static void reass_dgram_destroy(reass_dgram_t *);
errno_t inet_reass_queue_packet(inet_packet_t *packet)
{
reass_dgram_t *rdg;
errno_t rc;
log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_reass_queue_packet()");
fibril_mutex_lock(&reass_dgram_map_lock);
rdg = reass_dgram_get(packet);
if (rdg == NULL) {
fibril_mutex_unlock(&reass_dgram_map_lock);
log_msg(LOG_DEFAULT, LVL_DEBUG, "Allocation failed, packet dropped.");
return ENOMEM;
}
rc = reass_dgram_insert_frag(rdg, packet);
if (rc != EOK)
return ENOMEM;
if (reass_dgram_complete(rdg)) {
reass_dgram_remove(rdg);
fibril_mutex_unlock(&reass_dgram_map_lock);
rc = reass_dgram_deliver(rdg);
reass_dgram_destroy(rdg);
return rc;
}
fibril_mutex_unlock(&reass_dgram_map_lock);
return EOK;
}
static reass_dgram_t *reass_dgram_get(inet_packet_t *packet)
{
assert(fibril_mutex_is_locked(&reass_dgram_map_lock));
list_foreach(reass_dgram_map, map_link, reass_dgram_t, rdg) {
link_t *f1_link = list_first(&rdg->frags);
assert(f1_link != NULL);
reass_frag_t *f1 = list_get_instance(f1_link, reass_frag_t,
dgram_link);
if ((inet_addr_compare(&f1->packet.src, &packet->src)) &&
(inet_addr_compare(&f1->packet.dest, &packet->dest)) &&
(f1->packet.proto == packet->proto) &&
(f1->packet.ident == packet->ident)) {
return rdg;
}
}
return reass_dgram_new();
}
static reass_dgram_t *reass_dgram_new(void)
{
reass_dgram_t *rdg;
rdg = calloc(1, sizeof(reass_dgram_t));
if (rdg == NULL)
return NULL;
list_append(&rdg->map_link, &reass_dgram_map);
list_initialize(&rdg->frags);
return rdg;
}
static reass_frag_t *reass_frag_new(void)
{
reass_frag_t *frag;
frag = calloc(1, sizeof(reass_frag_t));
if (frag == NULL)
return NULL;
link_initialize(&frag->dgram_link);
return frag;
}
static errno_t reass_dgram_insert_frag(reass_dgram_t *rdg, inet_packet_t *packet)
{
reass_frag_t *frag;
void *data_copy;
link_t *link;
assert(fibril_mutex_is_locked(&reass_dgram_map_lock));
frag = reass_frag_new();
data_copy = malloc(packet->size);
if (data_copy == NULL) {
free(frag);
return ENOMEM;
}
memcpy(data_copy, packet->data, packet->size);
frag->packet = *packet;
frag->packet.data = data_copy;
link = list_first(&rdg->frags);
while (link != NULL) {
reass_frag_t *qf = list_get_instance(link, reass_frag_t,
dgram_link);
if (qf->packet.offs >= packet->offs)
break;
link = list_next(link, &rdg->frags);
}
if (link != NULL)
list_insert_after(&frag->dgram_link, link);
else
list_append(&frag->dgram_link, &rdg->frags);
return EOK;
}
static bool reass_dgram_complete(reass_dgram_t *rdg)
{
reass_frag_t *frag, *prev;
link_t *link;
assert(fibril_mutex_is_locked(&reass_dgram_map_lock));
assert(!list_empty(&rdg->frags));
link = list_first(&rdg->frags);
assert(link != NULL);
frag = list_get_instance(link, reass_frag_t,
dgram_link);
if (frag->packet.offs != 0)
return false;
prev = frag;
while (true) {
link = list_next(link, &rdg->frags);
if (link == NULL)
break;
frag = list_get_instance(link, reass_frag_t, dgram_link);
if (frag->packet.offs > prev->packet.offs + prev->packet.size)
return false;
if (!frag->packet.mf)
return true;
prev = frag;
}
return false;
}
static void reass_dgram_remove(reass_dgram_t *rdg)
{
assert(fibril_mutex_is_locked(&reass_dgram_map_lock));
list_remove(&rdg->map_link);
}
static errno_t reass_dgram_deliver(reass_dgram_t *rdg)
{
size_t dgram_size;
size_t fragoff_limit;
inet_dgram_t dgram;
uint8_t proto;
reass_frag_t *frag;
errno_t rc;
frag = NULL;
list_foreach(rdg->frags, dgram_link, reass_frag_t, cfrag) {
if (!cfrag->packet.mf) {
frag = cfrag;
break;
}
}
assert(frag != NULL);
assert(!frag->packet.mf);
dgram_size = frag->packet.offs + frag->packet.size;
fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l + 1);
if (dgram_size > FRAG_OFFS_UNIT * fragoff_limit)
return ELIMIT;
dgram.data = calloc(dgram_size, 1);
if (dgram.data == NULL)
return ENOMEM;
dgram.iplink = frag->packet.link_id;
dgram.size = dgram_size;
dgram.src = frag->packet.src;
dgram.dest = frag->packet.dest;
dgram.tos = frag->packet.tos;
proto = frag->packet.proto;
size_t doffs = 0;
list_foreach(rdg->frags, dgram_link, reass_frag_t, cfrag) {
size_t cb, ce;
cb = max(doffs, cfrag->packet.offs);
ce = min(dgram_size, cfrag->packet.offs + cfrag->packet.size);
if (ce > cb) {
memcpy(dgram.data + cb,
cfrag->packet.data + cb - cfrag->packet.offs,
ce - cb);
}
if (!cfrag->packet.mf)
break;
}
rc = inet_recv_dgram_local(&dgram, proto);
free(dgram.data);
return rc;
}
static void reass_dgram_destroy(reass_dgram_t *rdg)
{
while (!list_empty(&rdg->frags)) {
link_t *flink = list_first(&rdg->frags);
reass_frag_t *frag = list_get_instance(flink, reass_frag_t,
dgram_link);
list_remove(&frag->dgram_link);
free(frag->packet.data);
free(frag);
}
free(rdg);
}
HelenOS homepage, sources at GitHub