dynamic loading of network stack no longer needed
This commit is contained in:
391
ext/picotcp/modules/pico_fragments.c
Normal file
391
ext/picotcp/modules/pico_fragments.c
Normal file
@@ -0,0 +1,391 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
Authors: Laurens Miers, Daniele Lacamera
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
#include "pico_config.h"
|
||||
#ifdef PICO_SUPPORT_IPV6
|
||||
#include "pico_ipv6.h"
|
||||
#include "pico_icmp6.h"
|
||||
#endif
|
||||
#ifdef PICO_SUPPORT_IPV4
|
||||
#include "pico_ipv4.h"
|
||||
#include "pico_icmp4.h"
|
||||
#endif
|
||||
#include "pico_stack.h"
|
||||
#include "pico_eth.h"
|
||||
#include "pico_udp.h"
|
||||
#include "pico_tcp.h"
|
||||
#include "pico_socket.h"
|
||||
#include "pico_device.h"
|
||||
#include "pico_tree.h"
|
||||
#include "pico_constants.h"
|
||||
#include "pico_fragments.h"
|
||||
|
||||
#define frag_dbg(...) do {} while(0)
|
||||
|
||||
#if defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_IPV6FRAG)
|
||||
#define IP6_FRAG_OFF(x) ((x & 0xFFF8u))
|
||||
#define IP6_FRAG_MORE(x) ((x & 0x0001))
|
||||
#define IP6_FRAG_ID(x) ((uint32_t)((x->ext.frag.id[0] << 24) + (x->ext.frag.id[1] << 16) + \
|
||||
(x->ext.frag.id[2] << 8) + x->ext.frag.id[3]))
|
||||
#else
|
||||
#define IP6_FRAG_OFF(x) (0)
|
||||
#define IP6_FRAG_MORE(x) (0)
|
||||
#define IP6_FRAG_ID(x) (0)
|
||||
#endif
|
||||
|
||||
#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG)
|
||||
#define IP4_FRAG_OFF(frag) (((uint32_t)frag & PICO_IPV4_FRAG_MASK) << 3ul)
|
||||
#define IP4_FRAG_MORE(frag) ((frag & PICO_IPV4_MOREFRAG) ? 1 : 0)
|
||||
#define IP4_FRAG_ID(hdr) (hdr->id)
|
||||
#else
|
||||
#define IP4_FRAG_OFF(frag) (0)
|
||||
#define IP4_FRAG_MORE(frag) (0)
|
||||
#define IP4_FRAG_ID(hdr) (0)
|
||||
#endif
|
||||
|
||||
#define FRAG_OFF(net, frag) ((net == PICO_PROTO_IPV4) ? (IP4_FRAG_OFF(frag)) : (IP6_FRAG_OFF(frag)))
|
||||
#define FRAG_MORE(net, frag) ((net == PICO_PROTO_IPV4) ? (IP4_FRAG_MORE(frag)) : (IP6_FRAG_MORE(frag)))
|
||||
|
||||
#define PICO_IPV6_FRAG_TIMEOUT 60000
|
||||
#define PICO_IPV4_FRAG_TIMEOUT 15000
|
||||
|
||||
static void pico_frag_expire(pico_time now, void *arg);
|
||||
static void pico_fragments_complete(unsigned int bookmark, uint8_t proto, uint8_t net);
|
||||
static int pico_fragments_check_complete(uint8_t proto, uint8_t net);
|
||||
|
||||
#if defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_IPV6FRAG)
|
||||
static uint32_t ipv6_cur_frag_id = 0u;
|
||||
uint32_t ipv6_fragments_timer = 0u;
|
||||
|
||||
static int pico_ipv6_frag_compare(void *ka, void *kb)
|
||||
{
|
||||
struct pico_frame *a = ka, *b = kb;
|
||||
if (IP6_FRAG_OFF(a->frag) > IP6_FRAG_OFF(b->frag))
|
||||
return 1;
|
||||
|
||||
if (IP6_FRAG_OFF(a->frag) < IP6_FRAG_OFF(b->frag))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
PICO_TREE_DECLARE(ipv6_fragments, pico_ipv6_frag_compare);
|
||||
|
||||
static void pico_ipv6_fragments_complete(unsigned int len, uint8_t proto)
|
||||
{
|
||||
struct pico_tree_node *index, *tmp;
|
||||
struct pico_frame *f;
|
||||
unsigned int bookmark = 0;
|
||||
struct pico_frame *full = NULL;
|
||||
struct pico_frame *first = pico_tree_first(&ipv6_fragments);
|
||||
|
||||
full = pico_frame_alloc((uint16_t)(PICO_SIZE_IP6HDR + len));
|
||||
if (full) {
|
||||
full->net_hdr = full->buffer;
|
||||
full->net_len = PICO_SIZE_IP6HDR;
|
||||
memcpy(full->net_hdr, first->net_hdr, full->net_len);
|
||||
full->transport_hdr = full->net_hdr + full->net_len;
|
||||
full->transport_len = (uint16_t)len;
|
||||
full->dev = first->dev;
|
||||
pico_tree_foreach_safe(index, &ipv6_fragments, tmp) {
|
||||
f = index->keyValue;
|
||||
memcpy(full->transport_hdr + bookmark, f->transport_hdr, f->transport_len);
|
||||
bookmark += f->transport_len;
|
||||
pico_tree_delete(&ipv6_fragments, f);
|
||||
pico_frame_discard(f);
|
||||
}
|
||||
if (pico_transport_receive(full, proto) == -1)
|
||||
{
|
||||
pico_frame_discard(full);
|
||||
}
|
||||
pico_timer_cancel(ipv6_fragments_timer);
|
||||
ipv6_fragments_timer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void pico_ipv6_frag_timer_on(void)
|
||||
{
|
||||
ipv6_fragments_timer = pico_timer_add(PICO_IPV6_FRAG_TIMEOUT, pico_frag_expire, &ipv6_fragments);
|
||||
}
|
||||
|
||||
static int pico_ipv6_frag_match(struct pico_frame *a, struct pico_frame *b)
|
||||
{
|
||||
struct pico_ipv6_hdr *ha, *hb;
|
||||
if (!a || !b)
|
||||
return 0;
|
||||
|
||||
ha = (struct pico_ipv6_hdr *)a->net_hdr;
|
||||
hb = (struct pico_ipv6_hdr *)b->net_hdr;
|
||||
if (!ha || !hb)
|
||||
return 0;
|
||||
|
||||
if (memcmp(ha->src.addr, hb->src.addr, PICO_SIZE_IP6) != 0)
|
||||
return 0;
|
||||
|
||||
if (memcmp(ha->dst.addr, hb->dst.addr, PICO_SIZE_IP6) != 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG)
|
||||
static uint32_t ipv4_cur_frag_id = 0u;
|
||||
uint32_t ipv4_fragments_timer = 0u;
|
||||
|
||||
static int pico_ipv4_frag_compare(void *ka, void *kb)
|
||||
{
|
||||
struct pico_frame *a = ka, *b = kb;
|
||||
if (IP4_FRAG_OFF(a->frag) > IP4_FRAG_OFF(b->frag))
|
||||
return 1;
|
||||
|
||||
if (IP4_FRAG_OFF(a->frag) < IP4_FRAG_OFF(b->frag))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
PICO_TREE_DECLARE(ipv4_fragments, pico_ipv4_frag_compare);
|
||||
|
||||
static void pico_ipv4_fragments_complete(unsigned int len, uint8_t proto)
|
||||
{
|
||||
struct pico_tree_node *index, *tmp;
|
||||
struct pico_frame *f;
|
||||
unsigned int bookmark = 0;
|
||||
struct pico_frame *full = NULL;
|
||||
struct pico_frame *first = pico_tree_first(&ipv4_fragments);
|
||||
|
||||
full = pico_frame_alloc((uint16_t)(PICO_SIZE_IP4HDR + len));
|
||||
if (full) {
|
||||
full->net_hdr = full->buffer;
|
||||
full->net_len = PICO_SIZE_IP4HDR;
|
||||
memcpy(full->net_hdr, first->net_hdr, full->net_len);
|
||||
full->transport_hdr = full->net_hdr + full->net_len;
|
||||
full->transport_len = (uint16_t)len;
|
||||
full->dev = first->dev;
|
||||
pico_tree_foreach_safe(index, &ipv4_fragments, tmp) {
|
||||
f = index->keyValue;
|
||||
memcpy(full->transport_hdr + bookmark, f->transport_hdr, f->transport_len);
|
||||
bookmark += f->transport_len;
|
||||
pico_tree_delete(&ipv4_fragments, f);
|
||||
pico_frame_discard(f);
|
||||
}
|
||||
ipv4_cur_frag_id = 0;
|
||||
if (pico_transport_receive(full, proto) == -1)
|
||||
{
|
||||
pico_frame_discard(full);
|
||||
}
|
||||
pico_timer_cancel(ipv4_fragments_timer);
|
||||
ipv4_fragments_timer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void pico_ipv4_frag_timer_on(void)
|
||||
{
|
||||
ipv4_fragments_timer = pico_timer_add( PICO_IPV4_FRAG_TIMEOUT, pico_frag_expire, &ipv4_fragments);
|
||||
}
|
||||
|
||||
static int pico_ipv4_frag_match(struct pico_frame *a, struct pico_frame *b)
|
||||
{
|
||||
struct pico_ipv4_hdr *ha, *hb;
|
||||
if (!a || !b)
|
||||
return 0;
|
||||
|
||||
ha = (struct pico_ipv4_hdr *)a->net_hdr;
|
||||
hb = (struct pico_ipv4_hdr *)b->net_hdr;
|
||||
if (!ha || !hb)
|
||||
return 0;
|
||||
|
||||
if (memcmp(&(ha->src.addr), &(hb->src.addr), PICO_SIZE_IP4) != 0)
|
||||
return 0;
|
||||
|
||||
if (memcmp(&(ha->dst.addr), &(hb->dst.addr), PICO_SIZE_IP4) != 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void pico_fragments_complete(unsigned int bookmark, uint8_t proto, uint8_t net)
|
||||
{
|
||||
if (0) {}
|
||||
|
||||
#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG)
|
||||
else if (net == PICO_PROTO_IPV4)
|
||||
{
|
||||
pico_ipv4_fragments_complete(bookmark, proto);
|
||||
}
|
||||
#endif
|
||||
#if defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_IPV6FRAG)
|
||||
else if (net == PICO_PROTO_IPV6)
|
||||
{
|
||||
pico_ipv6_fragments_complete(bookmark, proto);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int pico_fragments_check_complete(uint8_t proto, uint8_t net)
|
||||
{
|
||||
struct pico_tree_node *index, *temp;
|
||||
struct pico_frame *cur;
|
||||
unsigned int bookmark = 0;
|
||||
struct pico_tree *tree = NULL;
|
||||
|
||||
#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG)
|
||||
if (net == PICO_PROTO_IPV4)
|
||||
{
|
||||
tree = &ipv4_fragments;
|
||||
}
|
||||
#endif
|
||||
#if defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_IPV6FRAG)
|
||||
if (net == PICO_PROTO_IPV6)
|
||||
{
|
||||
tree = &ipv6_fragments;
|
||||
}
|
||||
#endif
|
||||
|
||||
pico_tree_foreach_safe(index, tree, temp) {
|
||||
cur = index->keyValue;
|
||||
if (FRAG_OFF(net, cur->frag) != bookmark)
|
||||
return 0;
|
||||
|
||||
bookmark += cur->transport_len;
|
||||
if (!FRAG_MORE(net, cur->frag)) {
|
||||
pico_fragments_complete(bookmark, proto, net);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pico_frag_expire(pico_time now, void *arg)
|
||||
{
|
||||
struct pico_tree_node *index, *tmp;
|
||||
struct pico_frame *f = NULL;
|
||||
struct pico_tree *tree = (struct pico_tree *) arg;
|
||||
struct pico_frame *first = NULL;
|
||||
uint8_t net = 0;
|
||||
(void)now;
|
||||
|
||||
if (!tree)
|
||||
{
|
||||
frag_dbg("Expired packet but no tree supplied!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
first = pico_tree_first(tree);
|
||||
|
||||
if (!first) {
|
||||
frag_dbg("not first - not sending notify\n");
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG)
|
||||
if (IS_IPV4(first))
|
||||
{
|
||||
net = PICO_PROTO_IPV4;
|
||||
frag_dbg("Packet expired! ID:%hu\n", ipv4_cur_frag_id);
|
||||
}
|
||||
#endif
|
||||
#if defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_IPV6FRAG)
|
||||
if (IS_IPV6(first))
|
||||
{
|
||||
net = PICO_PROTO_IPV6;
|
||||
frag_dbg("Packet expired! ID:%hu\n", ipv6_cur_frag_id);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Empty the tree */
|
||||
pico_tree_foreach_safe(index, tree, tmp) {
|
||||
f = index->keyValue;
|
||||
pico_tree_delete(tree, f);
|
||||
if (f != first)
|
||||
pico_frame_discard(f); /* Later, after ICMP notification...*/
|
||||
|
||||
}
|
||||
|
||||
if (((FRAG_OFF(net, first->frag) == 0) && (pico_frame_dst_is_unicast(first))))
|
||||
{
|
||||
frag_dbg("sending notify\n");
|
||||
pico_notify_frag_expired(first);
|
||||
}
|
||||
|
||||
if (f)
|
||||
pico_tree_delete(tree, f);
|
||||
|
||||
pico_frame_discard(first);
|
||||
}
|
||||
|
||||
void pico_ipv6_process_frag(struct pico_ipv6_exthdr *frag, struct pico_frame *f, uint8_t proto)
|
||||
{
|
||||
#if defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_IPV6FRAG)
|
||||
struct pico_frame *first = pico_tree_first(&ipv6_fragments);
|
||||
|
||||
if (!first) {
|
||||
if (ipv6_cur_frag_id && (IP6_FRAG_ID(frag) == ipv6_cur_frag_id)) {
|
||||
/* Discard late arrivals, without firing the timer. */
|
||||
frag_dbg("discarded late arrival, exp:%hu found:%hu\n", ipv6_cur_frag_id, IP6_FRAG_ID(frag));
|
||||
return;
|
||||
}
|
||||
|
||||
pico_ipv6_frag_timer_on();
|
||||
ipv6_cur_frag_id = IP6_FRAG_ID(frag);
|
||||
frag_dbg("Started new reassembly, ID:%hu\n", ipv6_cur_frag_id);
|
||||
}
|
||||
|
||||
if (!first || (pico_ipv6_frag_match(f, first) && (IP6_FRAG_ID(frag) == ipv6_cur_frag_id))) {
|
||||
pico_tree_insert(&ipv6_fragments, pico_frame_copy(f));
|
||||
}
|
||||
|
||||
pico_fragments_check_complete(proto, PICO_PROTO_IPV6);
|
||||
#else
|
||||
IGNORE_PARAMETER(frag);
|
||||
IGNORE_PARAMETER(f);
|
||||
IGNORE_PARAMETER(proto);
|
||||
#endif
|
||||
}
|
||||
|
||||
void pico_ipv4_process_frag(struct pico_ipv4_hdr *hdr, struct pico_frame *f, uint8_t proto)
|
||||
{
|
||||
#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG)
|
||||
struct pico_frame *first = pico_tree_first(&ipv4_fragments);
|
||||
|
||||
/* fragments from old packets still in tree, and new first fragment ? */
|
||||
if (first && (IP4_FRAG_ID(hdr) != ipv4_cur_frag_id) && (IP4_FRAG_OFF(f->frag) == 0))
|
||||
{
|
||||
/* Empty the tree */
|
||||
struct pico_tree_node *index, *tmp;
|
||||
pico_tree_foreach_safe(index, &ipv4_fragments, tmp) {
|
||||
struct pico_frame * old = index->keyValue;
|
||||
pico_tree_delete(&ipv4_fragments, old);
|
||||
pico_frame_discard(old);
|
||||
}
|
||||
first = NULL;
|
||||
ipv4_cur_frag_id = 0;
|
||||
}
|
||||
|
||||
f->frag = short_be(hdr->frag);
|
||||
if (!first) {
|
||||
if (ipv4_cur_frag_id && (IP4_FRAG_ID(hdr) == ipv4_cur_frag_id)) {
|
||||
/* Discard late arrivals, without firing the timer */
|
||||
return;
|
||||
}
|
||||
|
||||
pico_ipv4_frag_timer_on();
|
||||
ipv4_cur_frag_id = IP4_FRAG_ID(hdr);
|
||||
}
|
||||
|
||||
if (!first || (pico_ipv4_frag_match(f, first) && (IP4_FRAG_ID(hdr) == ipv4_cur_frag_id))) {
|
||||
pico_tree_insert(&ipv4_fragments, pico_frame_copy(f));
|
||||
}
|
||||
|
||||
pico_fragments_check_complete(proto, PICO_PROTO_IPV4);
|
||||
#else
|
||||
IGNORE_PARAMETER(hdr);
|
||||
IGNORE_PARAMETER(f);
|
||||
IGNORE_PARAMETER(proto);
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user