picotcp initial commit - missing files
This commit is contained in:
parent
aad38f965b
commit
ce3d8f2baa
|
@ -0,0 +1 @@
|
||||||
|
OPTIONS+=-DPICO_SUPPORT_CRC
|
|
@ -0,0 +1,207 @@
|
||||||
|
DEBUG_ALL?=0
|
||||||
|
|
||||||
|
DEBUG_ARP?=0
|
||||||
|
DEBUG_AODV?=0
|
||||||
|
DEBUG_PPP?=0
|
||||||
|
DEBUG_TAP_ALL?=0
|
||||||
|
DEBUG_TAP_GENERAL?=0
|
||||||
|
DEBUG_TAP_INFO?=0
|
||||||
|
DEBUG_TAP_WIN?=0
|
||||||
|
DEBUG_TAP_REG?=0
|
||||||
|
DEBUG_DHCP_CLIENT?=0
|
||||||
|
DEBUG_DHCP_SERVER?=0
|
||||||
|
DEBUG_DNS?=0
|
||||||
|
DEBUG_DNS_SD?=0
|
||||||
|
DEBUG_FRAG?=0
|
||||||
|
DEBUG_IGMP?=0
|
||||||
|
DEBUG_IPF?=0
|
||||||
|
DEBUG_MCAST?=0
|
||||||
|
DEBUG_IPV6?=0
|
||||||
|
DEBUG_IPV6_ROUTE?=0
|
||||||
|
DEBUG_IPV6_ND?=0
|
||||||
|
DEBUG_MDNS?=0
|
||||||
|
DEBUG_MLD?=0
|
||||||
|
DEBUG_MM?=0
|
||||||
|
DEBUG_NAT?=0
|
||||||
|
DEBUG_OLSR?=0
|
||||||
|
DEBUG_SLAACV4?=0
|
||||||
|
DEBUG_SNTP?=0
|
||||||
|
DEBUG_TCP_ALL?=0
|
||||||
|
DEBUG_TCP_NAGLE?=0
|
||||||
|
DEBUG_TCP_OPTIONS?=0
|
||||||
|
DEBUG_TCP_GENERAL?=0
|
||||||
|
DEBUG_TFTP?=0
|
||||||
|
DEBUG_UDP?=0
|
||||||
|
DEBUG_6LOWPAN?=0
|
||||||
|
DEBUG_RADIOTEST?=0
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_ALL),0)
|
||||||
|
DEBUG_ARP=1
|
||||||
|
DEBUG_AODV=1
|
||||||
|
DEBUG_PPP=1
|
||||||
|
DEBUG_TAP_ALL=1
|
||||||
|
DEBUG_DHCP_CLIENT=1
|
||||||
|
DEBUG_DHCP_SERVER=1
|
||||||
|
DEBUG_DNS=1
|
||||||
|
DEBUG_DNS_SD=1
|
||||||
|
DEBUG_FRAG=1
|
||||||
|
DEBUG_IGMP=1
|
||||||
|
DEBUG_IPF=1
|
||||||
|
DEBUG_MCAST=1
|
||||||
|
DEBUG_IPV6=1
|
||||||
|
DEBUG_IPV6_ROUTE=1
|
||||||
|
DEBUG_IPV6_ND=1
|
||||||
|
DEBUG_MDNS=1
|
||||||
|
DEBUG_MLD=1
|
||||||
|
DEBUG_MM=1
|
||||||
|
DEBUG_NAT=1
|
||||||
|
DEBUG_OLSR=1
|
||||||
|
DEBUG_SLAACV4=1
|
||||||
|
DEBUG_SNTP=1
|
||||||
|
DEBUG_TCP_ALL=1
|
||||||
|
DEBUG_TFTP=1
|
||||||
|
DEBUG_UDP=1
|
||||||
|
DEBUG_6LOWPAN=1
|
||||||
|
DEBUG_RADIOTEST=1
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_TCP_ALL),0)
|
||||||
|
DEBUG_TCP_NAGLE=1
|
||||||
|
DEBUG_TCP_OPTIONS=1
|
||||||
|
DEBUG_TCP_GENERAL=1
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_TAP_ALL),0)
|
||||||
|
DEBUG_TAP_GENERAL=1
|
||||||
|
DEBUG_TAP_INFO=1
|
||||||
|
DEBUG_TAP_WIN=1
|
||||||
|
DEBUG_TAP_REG=1
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_ARP),0)
|
||||||
|
CFLAGS+=-DDEBUG_ARP
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_AODV),0)
|
||||||
|
CFLAGS+=-DDEBUG_AODV
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_PPP),0)
|
||||||
|
CFLAGS+=-DDEBUG_PPP
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_TAP_GENERAL),0)
|
||||||
|
CFLAGS+=-DDEBUG_TAP_GENERAL
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_TAP_INFO),0)
|
||||||
|
CFLAGS+=-DDEBUG_TAP_INFO
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_TAP_WIN),0)
|
||||||
|
CFLAGS+=-DDEBUG_TAP_WIN
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_TAP_REG),0)
|
||||||
|
CFLAGS+=-DDEBUG_TAP_REG
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_DHCP_CLIENT),0)
|
||||||
|
CFLAGS+=-DDEBUG_DHCP_CLIENT
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_DHCP_SERVER),0)
|
||||||
|
CFLAGS+=-DDEBUG_DHCP_SERVER
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_DNS),0)
|
||||||
|
CFLAGS+=-DDEBUG_DNS
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_DNS_SD),0)
|
||||||
|
CFLAGS+=-DDEBUG_DNS_SD
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_FRAG),0)
|
||||||
|
CFLAGS+=-DDEBUG_FRAG
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_IGMP),0)
|
||||||
|
CFLAGS+=-DDEBUG_IGMP
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_IPF),0)
|
||||||
|
CFLAGS+=-DDEBUG_IPF
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_MCAST),0)
|
||||||
|
CFLAGS+=-DDEBUG_MCAST
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_IPV6),0)
|
||||||
|
CFLAGS+=-DDEBUG_IPV6
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_IPV6_ROUTE),0)
|
||||||
|
CFLAGS+=-DDEBUG_IPV6_ROUTE
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_IPV6_ND),0)
|
||||||
|
CFLAGS+=-DDEBUG_IPV6_ND
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_MDNS),0)
|
||||||
|
CFLAGS+=-DDEBUG_MDNS
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_MLD),0)
|
||||||
|
CFLAGS+=-DDEBUG_MLD
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_MM),0)
|
||||||
|
CFLAGS+=-DDEBUG_MM
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_NAT),0)
|
||||||
|
CFLAGS+=-DDEBUG_NAT
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_OLSR),0)
|
||||||
|
CFLAGS+=-DDEBUG_OLSR
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_SLAACV4),0)
|
||||||
|
CFLAGS+=-DDEBUG_SLAACV4
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_SNTP),0)
|
||||||
|
CFLAGS+=-DDEBUG_SNTP
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_TCP_NAGLE),0)
|
||||||
|
CFLAGS+=-DDEBUG_TCP_NAGLE
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_TCP_OPTIONS),0)
|
||||||
|
CFLAGS+=-DDEBUG_TCP_OPTIONS
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_TCP_GENERAL),0)
|
||||||
|
CFLAGS+=-DDEBUG_TCP_GENERAL
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_TFTP),0)
|
||||||
|
CFLAGS+=-DDEBUG_TFTP
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_UDP),0)
|
||||||
|
CFLAGS+=-DDEBUG_UDP
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_6LOWPAN),0)
|
||||||
|
CFLAGS+=-DDEBUG_6LOWPAN
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(DEBUG_RADIOTEST), 0)
|
||||||
|
CFLAGS+=-DDEBUG_RADIOTEST
|
||||||
|
endif
|
|
@ -0,0 +1,2 @@
|
||||||
|
OPTIONS+=-DPICO_SUPPORT_DHCPC
|
||||||
|
MOD_OBJ+=$(LIBBASE)modules/pico_dhcp_client.o $(LIBBASE)modules/pico_dhcp_common.o
|
|
@ -0,0 +1,2 @@
|
||||||
|
OPTIONS+=-DPICO_SUPPORT_DHCPD
|
||||||
|
MOD_OBJ+=$(LIBBASE)modules/pico_dhcp_server.o $(LIBBASE)modules/pico_dhcp_common.o
|
|
@ -0,0 +1,2 @@
|
||||||
|
OPTIONS+=-DPICO_SUPPORT_DNS_CLIENT
|
||||||
|
MOD_OBJ+=$(LIBBASE)modules/pico_dns_client.o $(LIBBASE)modules/pico_dns_common.o
|
|
@ -0,0 +1,3 @@
|
||||||
|
OPTIONS+=-DPICO_SUPPORT_ETH
|
||||||
|
MOD_OBJ+=$(LIBBASE)modules/pico_arp.o
|
||||||
|
MOD_OBJ+=$(LIBBASE)modules/pico_ethernet.o
|
|
@ -0,0 +1,5 @@
|
||||||
|
OPTIONS+=-DPICO_SUPPORT_ICMP4
|
||||||
|
MOD_OBJ+=$(LIBBASE)modules/pico_icmp4.o
|
||||||
|
ifneq ($(PING),0)
|
||||||
|
OPTIONS+=-DPICO_SUPPORT_PING
|
||||||
|
endif
|
|
@ -0,0 +1,2 @@
|
||||||
|
OPTIONS+=-DPICO_SUPPORT_IPV4
|
||||||
|
MOD_OBJ+=$(LIBBASE)modules/pico_ipv4.o
|
|
@ -0,0 +1,2 @@
|
||||||
|
OPTIONS+=-DPICO_SUPPORT_IPV4FRAG
|
||||||
|
MOD_OBJ+=$(LIBBASE)modules/pico_fragments.o
|
|
@ -0,0 +1,3 @@
|
||||||
|
OPTIONS+=-DPICO_SUPPORT_PPP
|
||||||
|
MOD_OBJ+=$(LIBBASE)modules/pico_dev_ppp.o
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
MOD_OBJ+=$(LIBBASE)modules/pico_dev_tap.o
|
|
@ -0,0 +1,3 @@
|
||||||
|
OPTIONS+=-DPICO_SUPPORT_TCP
|
||||||
|
MOD_OBJ+=$(LIBBASE)modules/pico_tcp.o
|
||||||
|
MOD_OBJ+=$(LIBBASE)modules/pico_socket_tcp.o
|
|
@ -0,0 +1 @@
|
||||||
|
MOD_OBJ+=$(LIBBASE)modules/pico_dev_tun.o
|
|
@ -0,0 +1,3 @@
|
||||||
|
OPTIONS+=-DPICO_SUPPORT_UDP
|
||||||
|
MOD_OBJ+=$(LIBBASE)modules/pico_udp.o
|
||||||
|
MOD_OBJ+=$(LIBBASE)modules/pico_socket_udp.o
|
|
@ -0,0 +1,482 @@
|
||||||
|
/*********************************************************************
|
||||||
|
PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved.
|
||||||
|
See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage.
|
||||||
|
|
||||||
|
.
|
||||||
|
|
||||||
|
Authors: Daniele Lacamera
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#include "pico_config.h"
|
||||||
|
#include "pico_device.h"
|
||||||
|
#include "pico_stack.h"
|
||||||
|
#include "pico_protocol.h"
|
||||||
|
#include "pico_tree.h"
|
||||||
|
#include "pico_ipv6.h"
|
||||||
|
#include "pico_ipv4.h"
|
||||||
|
#include "pico_icmp6.h"
|
||||||
|
#include "pico_eth.h"
|
||||||
|
#include "pico_802154.h"
|
||||||
|
#include "pico_6lowpan.h"
|
||||||
|
#include "pico_6lowpan_ll.h"
|
||||||
|
#include "pico_addressing.h"
|
||||||
|
#define PICO_DEVICE_DEFAULT_MTU (1500)
|
||||||
|
|
||||||
|
struct pico_devices_rr_info {
|
||||||
|
struct pico_tree_node *node_in, *node_out;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct pico_devices_rr_info Devices_rr_info = {
|
||||||
|
NULL, NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static int pico_dev_cmp(void *ka, void *kb)
|
||||||
|
{
|
||||||
|
struct pico_device *a = ka, *b = kb;
|
||||||
|
if (a->hash < b->hash)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
|
||||||
|
if (a->hash > b->hash)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PICO_TREE_DECLARE(Device_tree, pico_dev_cmp);
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_6LOWPAN
|
||||||
|
static struct pico_ipv6_link * pico_6lowpan_link_add(struct pico_device *dev, const struct pico_ip6 *prefix)
|
||||||
|
{
|
||||||
|
struct pico_ip6 netmask64 = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||||
|
struct pico_6lowpan_info *info = (struct pico_6lowpan_info *)dev->eth;
|
||||||
|
struct pico_ipv6_link *link = NULL; /* Make sure to return NULL */
|
||||||
|
struct pico_ip6 newaddr;
|
||||||
|
|
||||||
|
memcpy(newaddr.addr, prefix->addr, PICO_SIZE_IP6);
|
||||||
|
memcpy(newaddr.addr + 8, info->addr_ext.addr, SIZE_6LOWPAN_EXT);
|
||||||
|
newaddr.addr[8] = newaddr.addr[8] ^ 0x02; /* Toggle U/L bit */
|
||||||
|
|
||||||
|
/* RFC6775: No Duplicate Address Detection (DAD) is performed if
|
||||||
|
* EUI-64-based IPv6 addresses are used (as these addresses are assumed
|
||||||
|
* to be globally unique). */
|
||||||
|
if ((link = pico_ipv6_link_add_no_dad(dev, newaddr, netmask64))) {
|
||||||
|
if (pico_ipv6_is_linklocal(newaddr.addr))
|
||||||
|
pico_6lp_nd_start_soliciting(link, NULL);
|
||||||
|
else
|
||||||
|
pico_6lp_nd_register(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pico_6lowpan_store_info(struct pico_device *dev, const uint8_t *mac)
|
||||||
|
{
|
||||||
|
if ((dev->eth = PICO_ZALLOC(sizeof(struct pico_6lowpan_info)))) {
|
||||||
|
memcpy(dev->eth, mac, sizeof(struct pico_6lowpan_info));
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
pico_err = PICO_ERR_ENOMEM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_IPV6
|
||||||
|
static void device_init_ipv6_final(struct pico_device *dev, struct pico_ip6 *linklocal)
|
||||||
|
{
|
||||||
|
dev->hostvars.basetime = PICO_ND_REACHABLE_TIME;
|
||||||
|
/* RFC 4861 $6.3.2 value between 0.5 and 1.5 times basetime */
|
||||||
|
dev->hostvars.reachabletime = ((5 + (pico_rand() % 10)) * PICO_ND_REACHABLE_TIME) / 10;
|
||||||
|
dev->hostvars.retranstime = PICO_ND_RETRANS_TIMER;
|
||||||
|
pico_icmp6_router_solicitation(dev, linklocal, NULL);
|
||||||
|
dev->hostvars.hoplimit = PICO_IPV6_DEFAULT_HOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pico_ipv6_link *pico_ipv6_link_add_local(struct pico_device *dev, const struct pico_ip6 *prefix)
|
||||||
|
{
|
||||||
|
struct pico_ip6 netmask64 = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||||
|
struct pico_ipv6_link *link = NULL; /* Make sure to return NULL */
|
||||||
|
struct pico_ip6 newaddr;
|
||||||
|
|
||||||
|
if (0) {}
|
||||||
|
#ifdef PICO_SUPPORT_6LOWPAN
|
||||||
|
else if (PICO_DEV_IS_6LOWPAN(dev)) {
|
||||||
|
link = pico_6lowpan_link_add(dev, prefix);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else {
|
||||||
|
memcpy(newaddr.addr, prefix->addr, PICO_SIZE_IP6);
|
||||||
|
/* modified EUI-64 + invert universal/local bit */
|
||||||
|
newaddr.addr[8] = (dev->eth->mac.addr[0] ^ 0x02);
|
||||||
|
newaddr.addr[9] = dev->eth->mac.addr[1];
|
||||||
|
newaddr.addr[10] = dev->eth->mac.addr[2];
|
||||||
|
newaddr.addr[11] = 0xff;
|
||||||
|
newaddr.addr[12] = 0xfe;
|
||||||
|
newaddr.addr[13] = dev->eth->mac.addr[3];
|
||||||
|
newaddr.addr[14] = dev->eth->mac.addr[4];
|
||||||
|
newaddr.addr[15] = dev->eth->mac.addr[5];
|
||||||
|
if ((link = pico_ipv6_link_add(dev, newaddr, netmask64))) {
|
||||||
|
device_init_ipv6_final(dev, &newaddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
static int device_init_mac(struct pico_device *dev, const uint8_t *mac)
|
||||||
|
{
|
||||||
|
#ifdef PICO_SUPPORT_IPV6
|
||||||
|
struct pico_ip6 linklocal = {{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xff, 0xfe, 0xaa, 0xaa, 0xaa}};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (0) {}
|
||||||
|
#ifdef PICO_SUPPORT_6LOWPAN
|
||||||
|
else if (PICO_DEV_IS_6LOWPAN(dev)) {
|
||||||
|
if (pico_6lowpan_store_info(dev, mac))
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else {
|
||||||
|
if ((dev->eth = PICO_ZALLOC(sizeof(struct pico_ethdev)))) {
|
||||||
|
memcpy(dev->eth->mac.addr, mac, PICO_SIZE_ETH);
|
||||||
|
} else {
|
||||||
|
pico_err = PICO_ERR_ENOMEM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_IPV6
|
||||||
|
if (pico_ipv6_link_add_local(dev, &linklocal) == NULL) {
|
||||||
|
PICO_FREE(dev->q_in);
|
||||||
|
PICO_FREE(dev->q_out);
|
||||||
|
PICO_FREE(dev->eth);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pico_device_ipv6_random_ll(struct pico_device *dev)
|
||||||
|
{
|
||||||
|
#ifdef PICO_SUPPORT_IPV6
|
||||||
|
struct pico_ip6 linklocal = {{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xff, 0xfe, 0xaa, 0xaa, 0xaa}};
|
||||||
|
struct pico_ip6 netmask6 = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||||
|
uint32_t len = (uint32_t)strlen(dev->name);
|
||||||
|
if (strcmp(dev->name, "loop")) {
|
||||||
|
do {
|
||||||
|
/* privacy extension + unset universal/local and individual/group bit */
|
||||||
|
len = pico_rand();
|
||||||
|
linklocal.addr[8] = (uint8_t)((len & 0xffu) & (uint8_t)(~0x03));
|
||||||
|
linklocal.addr[9] = (uint8_t)(len >> 8);
|
||||||
|
linklocal.addr[10] = (uint8_t)(len >> 16);
|
||||||
|
linklocal.addr[11] = (uint8_t)(len >> 24);
|
||||||
|
len = pico_rand();
|
||||||
|
linklocal.addr[12] = (uint8_t)len;
|
||||||
|
linklocal.addr[13] = (uint8_t)(len >> 8);
|
||||||
|
linklocal.addr[14] = (uint8_t)(len >> 16);
|
||||||
|
linklocal.addr[15] = (uint8_t)(len >> 24);
|
||||||
|
pico_rand_feed(dev->hash);
|
||||||
|
} while (pico_ipv6_link_get(&linklocal));
|
||||||
|
|
||||||
|
if (pico_ipv6_link_add(dev, linklocal, netmask6) == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int device_init_nomac(struct pico_device *dev)
|
||||||
|
{
|
||||||
|
if (pico_device_ipv6_random_ll(dev) < 0) {
|
||||||
|
PICO_FREE(dev->q_in);
|
||||||
|
PICO_FREE(dev->q_out);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->eth = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEBUG_IPV6(ip) { \
|
||||||
|
char ipstr[40] = { 0 }; \
|
||||||
|
pico_ipv6_to_string(ipstr, (ip).addr); \
|
||||||
|
dbg("IPv6 (%s)\n", ipstr); \
|
||||||
|
}
|
||||||
|
|
||||||
|
int pico_device_init(struct pico_device *dev, const char *name, const uint8_t *mac)
|
||||||
|
{
|
||||||
|
uint32_t len = (uint32_t)strlen(name);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if(len > MAX_DEVICE_NAME)
|
||||||
|
len = MAX_DEVICE_NAME;
|
||||||
|
|
||||||
|
memcpy(dev->name, name, len);
|
||||||
|
dev->hash = pico_hash(dev->name, len);
|
||||||
|
|
||||||
|
Devices_rr_info.node_in = NULL;
|
||||||
|
Devices_rr_info.node_out = NULL;
|
||||||
|
dev->q_in = PICO_ZALLOC(sizeof(struct pico_queue));
|
||||||
|
if (!dev->q_in)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
dev->q_out = PICO_ZALLOC(sizeof(struct pico_queue));
|
||||||
|
if (!dev->q_out) {
|
||||||
|
PICO_FREE(dev->q_in);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pico_tree_insert(&Device_tree, dev)) {
|
||||||
|
PICO_FREE(dev->q_in);
|
||||||
|
PICO_FREE(dev->q_out);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!dev->mtu)
|
||||||
|
dev->mtu = PICO_DEVICE_DEFAULT_MTU;
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_6LOWPAN
|
||||||
|
if (PICO_DEV_IS_6LOWPAN(dev) && LL_MODE_ETHERNET == dev->mode)
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (mac) {
|
||||||
|
ret = device_init_mac(dev, mac);
|
||||||
|
} else {
|
||||||
|
if (!dev->mode) {
|
||||||
|
ret = device_init_nomac(dev);
|
||||||
|
}
|
||||||
|
#ifdef PICO_SUPPORT_6LOWPAN
|
||||||
|
else {
|
||||||
|
/* RFC6775: Link Local to be formed based on EUI-64 as per RFC6775 */
|
||||||
|
dbg("Link local address to be formed based on EUI-64\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pico_queue_destroy(struct pico_queue *q)
|
||||||
|
{
|
||||||
|
if (q) {
|
||||||
|
pico_queue_empty(q);
|
||||||
|
PICO_FREE(q);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pico_device_destroy(struct pico_device *dev)
|
||||||
|
{
|
||||||
|
|
||||||
|
pico_queue_destroy(dev->q_in);
|
||||||
|
pico_queue_destroy(dev->q_out);
|
||||||
|
|
||||||
|
if (!dev->mode && dev->eth)
|
||||||
|
PICO_FREE(dev->eth);
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_IPV4
|
||||||
|
pico_ipv4_cleanup_links(dev);
|
||||||
|
#endif
|
||||||
|
#ifdef PICO_SUPPORT_IPV6
|
||||||
|
pico_ipv6_cleanup_links(dev);
|
||||||
|
#endif
|
||||||
|
pico_tree_delete(&Device_tree, dev);
|
||||||
|
|
||||||
|
if (dev->destroy)
|
||||||
|
dev->destroy(dev);
|
||||||
|
|
||||||
|
Devices_rr_info.node_in = NULL;
|
||||||
|
Devices_rr_info.node_out = NULL;
|
||||||
|
PICO_FREE(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_dev_serve_interrupt(struct pico_device *dev, int loop_score)
|
||||||
|
{
|
||||||
|
if ((dev->__serving_interrupt) && (dev->dsr)) {
|
||||||
|
/* call dsr routine */
|
||||||
|
loop_score = dev->dsr(dev, loop_score);
|
||||||
|
}
|
||||||
|
|
||||||
|
return loop_score;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_dev_serve_polling(struct pico_device *dev, int loop_score)
|
||||||
|
{
|
||||||
|
if (dev->poll) {
|
||||||
|
loop_score = dev->poll(dev, loop_score);
|
||||||
|
}
|
||||||
|
|
||||||
|
return loop_score;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int devloop_in(struct pico_device *dev, int loop_score)
|
||||||
|
{
|
||||||
|
struct pico_frame *f;
|
||||||
|
while(loop_score > 0) {
|
||||||
|
if (dev->q_in->frames == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Receive */
|
||||||
|
f = pico_dequeue(dev->q_in);
|
||||||
|
if (f) {
|
||||||
|
pico_datalink_receive(f);
|
||||||
|
loop_score--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return loop_score;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int devloop_sendto_dev(struct pico_device *dev, struct pico_frame *f)
|
||||||
|
{
|
||||||
|
#ifdef PICO_SUPPORT_6LOWPAN
|
||||||
|
if (PICO_DEV_IS_6LOWPAN(dev)) {
|
||||||
|
return (pico_6lowpan_ll_sendto_dev(dev, f) <= 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return (dev->send(dev, f->start, (int)f->len) <= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int devloop_out(struct pico_device *dev, int loop_score)
|
||||||
|
{
|
||||||
|
struct pico_frame *f;
|
||||||
|
while(loop_score > 0) {
|
||||||
|
if (dev->q_out->frames == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Device dequeue + send */
|
||||||
|
f = pico_queue_peek(dev->q_out);
|
||||||
|
if (!f)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (devloop_sendto_dev(dev, f) == 0) { /* success. */
|
||||||
|
f = pico_dequeue(dev->q_out);
|
||||||
|
pico_frame_discard(f); /* SINGLE POINT OF DISCARD for OUTGOING FRAMES */
|
||||||
|
loop_score--;
|
||||||
|
} else
|
||||||
|
break; /* Don't discard */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return loop_score;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int devloop(struct pico_device *dev, int loop_score, int direction)
|
||||||
|
{
|
||||||
|
/* If device supports interrupts, read the value of the condition and trigger the dsr */
|
||||||
|
loop_score = check_dev_serve_interrupt(dev, loop_score);
|
||||||
|
|
||||||
|
/* If device supports polling, give control. Loop score is managed internally,
|
||||||
|
* remaining loop points are returned. */
|
||||||
|
loop_score = check_dev_serve_polling(dev, loop_score);
|
||||||
|
|
||||||
|
if (direction == PICO_LOOP_DIR_OUT)
|
||||||
|
loop_score = devloop_out(dev, loop_score);
|
||||||
|
else
|
||||||
|
loop_score = devloop_in(dev, loop_score);
|
||||||
|
|
||||||
|
return loop_score;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct pico_tree_node *pico_dev_roundrobin_start(int direction)
|
||||||
|
{
|
||||||
|
if (Devices_rr_info.node_in == NULL)
|
||||||
|
Devices_rr_info.node_in = pico_tree_firstNode(Device_tree.root);
|
||||||
|
|
||||||
|
if (Devices_rr_info.node_out == NULL)
|
||||||
|
Devices_rr_info.node_out = pico_tree_firstNode(Device_tree.root);
|
||||||
|
|
||||||
|
if (direction == PICO_LOOP_DIR_IN)
|
||||||
|
return Devices_rr_info.node_in;
|
||||||
|
else
|
||||||
|
return Devices_rr_info.node_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pico_dev_roundrobin_end(int direction, struct pico_tree_node *last)
|
||||||
|
{
|
||||||
|
if (direction == PICO_LOOP_DIR_IN)
|
||||||
|
Devices_rr_info.node_in = last;
|
||||||
|
else
|
||||||
|
Devices_rr_info.node_out = last;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEV_LOOP_MIN 16
|
||||||
|
|
||||||
|
int pico_devices_loop(int loop_score, int direction)
|
||||||
|
{
|
||||||
|
struct pico_device *start, *next;
|
||||||
|
struct pico_tree_node *next_node = pico_dev_roundrobin_start(direction);
|
||||||
|
|
||||||
|
if (!next_node)
|
||||||
|
return loop_score;
|
||||||
|
|
||||||
|
next = next_node->keyValue;
|
||||||
|
start = next;
|
||||||
|
|
||||||
|
/* round-robin all devices, break if traversed all devices */
|
||||||
|
while ((loop_score > DEV_LOOP_MIN) && (next != NULL)) {
|
||||||
|
loop_score = devloop(next, loop_score, direction);
|
||||||
|
next_node = pico_tree_next(next_node);
|
||||||
|
next = next_node->keyValue;
|
||||||
|
if (next == NULL)
|
||||||
|
{
|
||||||
|
next_node = pico_tree_firstNode(Device_tree.root);
|
||||||
|
next = next_node->keyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next == start)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pico_dev_roundrobin_end(direction, next_node);
|
||||||
|
return loop_score;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pico_device *pico_get_device(const char*name)
|
||||||
|
{
|
||||||
|
struct pico_device *dev;
|
||||||
|
struct pico_tree_node *index;
|
||||||
|
pico_tree_foreach(index, &Device_tree){
|
||||||
|
dev = index->keyValue;
|
||||||
|
if(strcmp(name, dev->name) == 0)
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t pico_device_broadcast(struct pico_frame *f)
|
||||||
|
{
|
||||||
|
struct pico_tree_node *index;
|
||||||
|
int32_t ret = -1;
|
||||||
|
|
||||||
|
pico_tree_foreach(index, &Device_tree)
|
||||||
|
{
|
||||||
|
struct pico_device *dev = index->keyValue;
|
||||||
|
if(dev != f->dev)
|
||||||
|
{
|
||||||
|
struct pico_frame *copy = pico_frame_copy(f);
|
||||||
|
|
||||||
|
if(!copy)
|
||||||
|
break;
|
||||||
|
|
||||||
|
copy->dev = dev;
|
||||||
|
copy->dev->send(copy->dev, copy->start, (int)copy->len);
|
||||||
|
pico_frame_discard(copy);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = f->dev->send(f->dev, f->start, (int)f->len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pico_device_link_state(struct pico_device *dev)
|
||||||
|
{
|
||||||
|
if (!dev->link_state)
|
||||||
|
return 1; /* Not supported, assuming link is always up */
|
||||||
|
|
||||||
|
return dev->link_state(dev);
|
||||||
|
}
|
|
@ -0,0 +1,329 @@
|
||||||
|
/*********************************************************************
|
||||||
|
PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved.
|
||||||
|
See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage.
|
||||||
|
|
||||||
|
.
|
||||||
|
|
||||||
|
Authors: Daniele Lacamera
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#include "pico_config.h"
|
||||||
|
#include "pico_frame.h"
|
||||||
|
#include "pico_protocol.h"
|
||||||
|
#include "pico_stack.h"
|
||||||
|
#include "pico_socket.h"
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_DEBUG_MEMORY
|
||||||
|
static int n_frames_allocated;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** frame alloc/dealloc/copy **/
|
||||||
|
void pico_frame_discard(struct pico_frame *f)
|
||||||
|
{
|
||||||
|
if (!f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
(*f->usage_count)--;
|
||||||
|
if (*f->usage_count == 0) {
|
||||||
|
if (f->flags & PICO_FRAME_FLAG_EXT_USAGE_COUNTER)
|
||||||
|
PICO_FREE(f->usage_count);
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_DEBUG_MEMORY
|
||||||
|
dbg("Discarded buffer @%p, caller: %p\n", f->buffer, __builtin_return_address(3));
|
||||||
|
dbg("DEBUG MEMORY: %d frames in use.\n", --n_frames_allocated);
|
||||||
|
#endif
|
||||||
|
if (!(f->flags & PICO_FRAME_FLAG_EXT_BUFFER))
|
||||||
|
PICO_FREE(f->buffer);
|
||||||
|
else if (f->notify_free)
|
||||||
|
f->notify_free(f->buffer);
|
||||||
|
|
||||||
|
if (f->info)
|
||||||
|
PICO_FREE(f->info);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_DEBUG_MEMORY
|
||||||
|
else {
|
||||||
|
dbg("Removed frame @%p(copy), usage count now: %d\n", f, *f->usage_count);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
PICO_FREE(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pico_frame *pico_frame_copy(struct pico_frame *f)
|
||||||
|
{
|
||||||
|
struct pico_frame *new = PICO_ZALLOC(sizeof(struct pico_frame));
|
||||||
|
if (!new)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memcpy(new, f, sizeof(struct pico_frame));
|
||||||
|
*(new->usage_count) += 1;
|
||||||
|
#ifdef PICO_SUPPORT_DEBUG_MEMORY
|
||||||
|
dbg("Copied frame @%p, into %p, usage count now: %d\n", f, new, *new->usage_count);
|
||||||
|
#endif
|
||||||
|
new->next = NULL;
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct pico_frame *pico_frame_do_alloc(uint32_t size, int zerocopy, int ext_buffer)
|
||||||
|
{
|
||||||
|
struct pico_frame *p = PICO_ZALLOC(sizeof(struct pico_frame));
|
||||||
|
uint32_t frame_buffer_size = size;
|
||||||
|
if (!p)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (ext_buffer && !zerocopy) {
|
||||||
|
/* external buffer implies zerocopy flag! */
|
||||||
|
PICO_FREE(p);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!zerocopy) {
|
||||||
|
unsigned int align = size % sizeof(uint32_t);
|
||||||
|
/* Ensure that usage_count starts on an aligned address */
|
||||||
|
if (align) {
|
||||||
|
frame_buffer_size += (uint32_t)sizeof(uint32_t) - align;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->buffer = PICO_ZALLOC((size_t)frame_buffer_size + sizeof(uint32_t));
|
||||||
|
if (!p->buffer) {
|
||||||
|
PICO_FREE(p);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->usage_count = (uint32_t *)(((uint8_t*)p->buffer) + frame_buffer_size);
|
||||||
|
} else {
|
||||||
|
p->buffer = NULL;
|
||||||
|
p->flags |= PICO_FRAME_FLAG_EXT_USAGE_COUNTER;
|
||||||
|
p->usage_count = PICO_ZALLOC(sizeof(uint32_t));
|
||||||
|
if (!p->usage_count) {
|
||||||
|
PICO_FREE(p);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p->buffer_len = size;
|
||||||
|
|
||||||
|
/* By default, frame content is the full buffer. */
|
||||||
|
p->start = p->buffer;
|
||||||
|
p->len = p->buffer_len;
|
||||||
|
*p->usage_count = 1;
|
||||||
|
p->net_hdr = p->buffer;
|
||||||
|
p->datalink_hdr = p->buffer;
|
||||||
|
p->transport_hdr = p->buffer;
|
||||||
|
p->app_hdr = p->buffer;
|
||||||
|
p->payload = p->buffer;
|
||||||
|
|
||||||
|
if (ext_buffer)
|
||||||
|
p->flags |= PICO_FRAME_FLAG_EXT_BUFFER;
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_DEBUG_MEMORY
|
||||||
|
dbg("Allocated buffer @%p, len= %d caller: %p\n", p->buffer, p->buffer_len, __builtin_return_address(2));
|
||||||
|
dbg("DEBUG MEMORY: %d frames in use.\n", ++n_frames_allocated);
|
||||||
|
#endif
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pico_frame *pico_frame_alloc(uint32_t size)
|
||||||
|
{
|
||||||
|
return pico_frame_do_alloc(size, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t *
|
||||||
|
pico_frame_new_buffer(struct pico_frame *f, uint32_t size, uint32_t *oldsize)
|
||||||
|
{
|
||||||
|
uint8_t *oldbuf;
|
||||||
|
uint32_t usage_count, *p_old_usage;
|
||||||
|
uint32_t frame_buffer_size;
|
||||||
|
unsigned int align;
|
||||||
|
|
||||||
|
if (!f || (size < f->buffer_len)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
align = size % sizeof(uint32_t);
|
||||||
|
frame_buffer_size = size;
|
||||||
|
if (align) {
|
||||||
|
frame_buffer_size += (uint32_t)sizeof(uint32_t) - align;
|
||||||
|
}
|
||||||
|
|
||||||
|
oldbuf = f->buffer;
|
||||||
|
*oldsize = f->buffer_len;
|
||||||
|
usage_count = *(f->usage_count);
|
||||||
|
p_old_usage = f->usage_count;
|
||||||
|
f->buffer = PICO_ZALLOC((size_t)frame_buffer_size + sizeof(uint32_t));
|
||||||
|
if (!f->buffer) {
|
||||||
|
f->buffer = oldbuf;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
f->usage_count = (uint32_t *)(((uint8_t*)f->buffer) + frame_buffer_size);
|
||||||
|
*f->usage_count = usage_count;
|
||||||
|
f->buffer_len = size;
|
||||||
|
|
||||||
|
if (f->flags & PICO_FRAME_FLAG_EXT_USAGE_COUNTER)
|
||||||
|
PICO_FREE(p_old_usage);
|
||||||
|
/* Now, the frame is not zerocopy anymore, and the usage counter has been moved within it */
|
||||||
|
return oldbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pico_frame_update_pointers(struct pico_frame *f, ptrdiff_t addr_diff, uint8_t *oldbuf)
|
||||||
|
{
|
||||||
|
f->net_hdr += addr_diff;
|
||||||
|
f->datalink_hdr += addr_diff;
|
||||||
|
f->transport_hdr += addr_diff;
|
||||||
|
f->app_hdr += addr_diff;
|
||||||
|
f->start += addr_diff;
|
||||||
|
f->payload += addr_diff;
|
||||||
|
|
||||||
|
if (!(f->flags & PICO_FRAME_FLAG_EXT_BUFFER))
|
||||||
|
PICO_FREE(oldbuf);
|
||||||
|
else if (f->notify_free)
|
||||||
|
f->notify_free(oldbuf);
|
||||||
|
|
||||||
|
f->flags = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pico_frame_grow_head(struct pico_frame *f, uint32_t size)
|
||||||
|
{
|
||||||
|
ptrdiff_t addr_diff = 0;
|
||||||
|
uint32_t oldsize = 0;
|
||||||
|
uint8_t *oldbuf = pico_frame_new_buffer(f, size, &oldsize);
|
||||||
|
if (!oldbuf)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Put old buffer at the end of new buffer */
|
||||||
|
memcpy(f->buffer + f->buffer_len - oldsize, oldbuf, (size_t)oldsize);
|
||||||
|
addr_diff = (ptrdiff_t)(f->buffer + f->buffer_len - oldsize - oldbuf);
|
||||||
|
|
||||||
|
return pico_frame_update_pointers(f, addr_diff, oldbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pico_frame_grow(struct pico_frame *f, uint32_t size)
|
||||||
|
{
|
||||||
|
ptrdiff_t addr_diff = 0;
|
||||||
|
uint32_t oldsize = 0;
|
||||||
|
uint8_t *oldbuf = pico_frame_new_buffer(f, size, &oldsize);
|
||||||
|
if (!oldbuf)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Just put old buffer at the beginning of new buffer */
|
||||||
|
memcpy(f->buffer, oldbuf, (size_t)oldsize);
|
||||||
|
addr_diff = (ptrdiff_t)(f->buffer - oldbuf);
|
||||||
|
|
||||||
|
return pico_frame_update_pointers(f, addr_diff, oldbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pico_frame *pico_frame_alloc_skeleton(uint32_t size, int ext_buffer)
|
||||||
|
{
|
||||||
|
return pico_frame_do_alloc(size, 1, ext_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pico_frame_skeleton_set_buffer(struct pico_frame *f, void *buf)
|
||||||
|
{
|
||||||
|
if (!buf)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
f->buffer = (uint8_t *) buf;
|
||||||
|
f->start = f->buffer;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pico_frame *pico_frame_deepcopy(struct pico_frame *f)
|
||||||
|
{
|
||||||
|
struct pico_frame *new = pico_frame_alloc(f->buffer_len);
|
||||||
|
ptrdiff_t addr_diff;
|
||||||
|
unsigned char *buf;
|
||||||
|
uint32_t *uc;
|
||||||
|
if (!new)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Save the two key pointers... */
|
||||||
|
buf = new->buffer;
|
||||||
|
uc = new->usage_count;
|
||||||
|
|
||||||
|
/* Overwrite all fields with originals */
|
||||||
|
memcpy(new, f, sizeof(struct pico_frame));
|
||||||
|
|
||||||
|
/* ...restore the two key pointers */
|
||||||
|
new->buffer = buf;
|
||||||
|
new->usage_count = uc;
|
||||||
|
|
||||||
|
/* Update in-buffer pointers with offset */
|
||||||
|
addr_diff = (ptrdiff_t)(new->buffer - f->buffer);
|
||||||
|
new->datalink_hdr += addr_diff;
|
||||||
|
new->net_hdr += addr_diff;
|
||||||
|
new->transport_hdr += addr_diff;
|
||||||
|
new->app_hdr += addr_diff;
|
||||||
|
new->start += addr_diff;
|
||||||
|
new->payload += addr_diff;
|
||||||
|
|
||||||
|
if (f->info) {
|
||||||
|
new->info = PICO_ZALLOC(sizeof(struct pico_remote_endpoint));
|
||||||
|
if (!new->info) {
|
||||||
|
pico_frame_discard(new);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memcpy(new->info, f->info, sizeof(struct pico_remote_endpoint));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_DEBUG_MEMORY
|
||||||
|
dbg("Deep-Copied frame @%p, into %p, usage count now: %d\n", f, new, *new->usage_count);
|
||||||
|
#endif
|
||||||
|
new->next = NULL;
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline uint32_t pico_checksum_adder(uint32_t sum, void *data, uint32_t len)
|
||||||
|
{
|
||||||
|
uint16_t *buf = (uint16_t *)data;
|
||||||
|
uint16_t *stop;
|
||||||
|
|
||||||
|
if (len & 0x01) {
|
||||||
|
--len;
|
||||||
|
#ifdef PICO_BIGENDIAN
|
||||||
|
sum += (((uint8_t *)data)[len]) << 8;
|
||||||
|
#else
|
||||||
|
sum += ((uint8_t *)data)[len];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
stop = (uint16_t *)(((uint8_t *)data) + len);
|
||||||
|
|
||||||
|
while (buf < stop) {
|
||||||
|
sum += *buf++;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint16_t pico_checksum_finalize(uint32_t sum)
|
||||||
|
{
|
||||||
|
while (sum >> 16) { /* a second carry is possible! */
|
||||||
|
sum = (sum & 0x0000FFFF) + (sum >> 16);
|
||||||
|
}
|
||||||
|
return short_be((uint16_t) ~sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate checksum of a given string
|
||||||
|
*/
|
||||||
|
uint16_t pico_checksum(void *inbuf, uint32_t len)
|
||||||
|
{
|
||||||
|
uint32_t sum;
|
||||||
|
|
||||||
|
sum = pico_checksum_adder(0, inbuf, len);
|
||||||
|
return pico_checksum_finalize(sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* WARNING: len1 MUST be an EVEN number */
|
||||||
|
uint16_t pico_dualbuffer_checksum(void *inbuf1, uint32_t len1, void *inbuf2, uint32_t len2)
|
||||||
|
{
|
||||||
|
uint32_t sum;
|
||||||
|
|
||||||
|
sum = pico_checksum_adder(0, inbuf1, len1);
|
||||||
|
sum = pico_checksum_adder(sum, inbuf2, len2);
|
||||||
|
return pico_checksum_finalize(sum);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* PicoTCP. Copyright (c) 2015-2017 Altran Intelligent Systems. Some rights reserved.
|
||||||
|
* See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage.
|
||||||
|
*
|
||||||
|
* Authors: Daniele Lacamera
|
||||||
|
* *********************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include <pico_md5.h>
|
||||||
|
|
||||||
|
#if defined (PICO_SUPPORT_CYASSL)
|
||||||
|
#include <cyassl/ctaocrypt/md5.h>
|
||||||
|
|
||||||
|
void pico_md5sum(uint8_t *dst, const uint8_t *src, size_t len)
|
||||||
|
{
|
||||||
|
Md5 md5;
|
||||||
|
InitMd5(&md5);
|
||||||
|
Md5Update(&md5, src, len);
|
||||||
|
Md5Final(&md5, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined (PICO_SUPPORT_POLARSSL)
|
||||||
|
#include <polarssl/md5.h>
|
||||||
|
|
||||||
|
void pico_md5sum(uint8_t *dst, const uint8_t *src, size_t len)
|
||||||
|
{
|
||||||
|
md5(src, len, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
static void (*do_pico_md5sum)(uint8_t *dst, const uint8_t *src, size_t len);
|
||||||
|
void pico_md5sum(uint8_t *dst, const uint8_t *src, size_t len)
|
||||||
|
{
|
||||||
|
if (do_pico_md5sum) {
|
||||||
|
do_pico_md5sum(dst, src, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pico_register_md5sum(void (*md5)(uint8_t *, const uint8_t *, size_t))
|
||||||
|
{
|
||||||
|
do_pico_md5sum = md5;
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,226 @@
|
||||||
|
/*********************************************************************
|
||||||
|
PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved.
|
||||||
|
See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage.
|
||||||
|
|
||||||
|
.
|
||||||
|
|
||||||
|
Authors: Daniele Lacamera
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "pico_protocol.h"
|
||||||
|
#include "pico_tree.h"
|
||||||
|
|
||||||
|
struct pico_proto_rr
|
||||||
|
{
|
||||||
|
struct pico_tree *t;
|
||||||
|
struct pico_tree_node *node_in, *node_out;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static int pico_proto_cmp(void *ka, void *kb)
|
||||||
|
{
|
||||||
|
struct pico_protocol *a = ka, *b = kb;
|
||||||
|
if (a->hash < b->hash)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (a->hash > b->hash)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PICO_TREE_DECLARE(Datalink_proto_tree, pico_proto_cmp);
|
||||||
|
static PICO_TREE_DECLARE(Network_proto_tree, pico_proto_cmp);
|
||||||
|
static PICO_TREE_DECLARE(Transport_proto_tree, pico_proto_cmp);
|
||||||
|
static PICO_TREE_DECLARE(Socket_proto_tree, pico_proto_cmp);
|
||||||
|
|
||||||
|
/* Static variables to keep track of the round robin loop */
|
||||||
|
static struct pico_proto_rr proto_rr_datalink = {
|
||||||
|
&Datalink_proto_tree, NULL, NULL
|
||||||
|
};
|
||||||
|
static struct pico_proto_rr proto_rr_network = {
|
||||||
|
&Network_proto_tree, NULL, NULL
|
||||||
|
};
|
||||||
|
static struct pico_proto_rr proto_rr_transport = {
|
||||||
|
&Transport_proto_tree, NULL, NULL
|
||||||
|
};
|
||||||
|
static struct pico_proto_rr proto_rr_socket = {
|
||||||
|
&Socket_proto_tree, NULL, NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static int proto_loop_in(struct pico_protocol *proto, int loop_score)
|
||||||
|
{
|
||||||
|
struct pico_frame *f;
|
||||||
|
while(loop_score > 0) {
|
||||||
|
if (proto->q_in->frames == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
f = pico_dequeue(proto->q_in);
|
||||||
|
if ((f) && (proto->process_in(proto, f) > 0)) {
|
||||||
|
loop_score--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return loop_score;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int proto_loop_out(struct pico_protocol *proto, int loop_score)
|
||||||
|
{
|
||||||
|
struct pico_frame *f;
|
||||||
|
while(loop_score > 0) {
|
||||||
|
if (proto->q_out->frames == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
f = pico_dequeue(proto->q_out);
|
||||||
|
if ((f) && (proto->process_out(proto, f) > 0)) {
|
||||||
|
loop_score--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return loop_score;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int proto_loop(struct pico_protocol *proto, int loop_score, int direction)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (direction == PICO_LOOP_DIR_IN)
|
||||||
|
loop_score = proto_loop_in(proto, loop_score);
|
||||||
|
else if (direction == PICO_LOOP_DIR_OUT)
|
||||||
|
loop_score = proto_loop_out(proto, loop_score);
|
||||||
|
|
||||||
|
return loop_score;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct pico_tree_node *roundrobin_init(struct pico_proto_rr *rr, int direction)
|
||||||
|
{
|
||||||
|
struct pico_tree_node *next_node = NULL;
|
||||||
|
/* Initialization (takes place only once) */
|
||||||
|
if (rr->node_in == NULL)
|
||||||
|
rr->node_in = pico_tree_firstNode(rr->t->root);
|
||||||
|
|
||||||
|
if (rr->node_out == NULL)
|
||||||
|
rr->node_out = pico_tree_firstNode(rr->t->root);
|
||||||
|
|
||||||
|
if (direction == PICO_LOOP_DIR_IN)
|
||||||
|
next_node = rr->node_in;
|
||||||
|
else
|
||||||
|
next_node = rr->node_out;
|
||||||
|
|
||||||
|
return next_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void roundrobin_end(struct pico_proto_rr *rr, int direction, struct pico_tree_node *last)
|
||||||
|
{
|
||||||
|
if (direction == PICO_LOOP_DIR_IN)
|
||||||
|
rr->node_in = last;
|
||||||
|
else
|
||||||
|
rr->node_out = last;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pico_protocol_generic_loop(struct pico_proto_rr *rr, int loop_score, int direction)
|
||||||
|
{
|
||||||
|
struct pico_protocol *start, *next;
|
||||||
|
struct pico_tree_node *next_node = roundrobin_init(rr, direction);
|
||||||
|
|
||||||
|
if (!next_node)
|
||||||
|
return loop_score;
|
||||||
|
|
||||||
|
next = next_node->keyValue;
|
||||||
|
|
||||||
|
/* init start node */
|
||||||
|
start = next;
|
||||||
|
|
||||||
|
/* round-robin all layer protocols, break if traversed all protocols */
|
||||||
|
while (loop_score > 1 && next != NULL) {
|
||||||
|
loop_score = proto_loop(next, loop_score, direction);
|
||||||
|
next_node = pico_tree_next(next_node);
|
||||||
|
next = next_node->keyValue;
|
||||||
|
if (next == NULL)
|
||||||
|
{
|
||||||
|
next_node = pico_tree_firstNode(rr->t->root);
|
||||||
|
next = next_node->keyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next == start)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
roundrobin_end(rr, direction, next_node);
|
||||||
|
return loop_score;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pico_protocol_datalink_loop(int loop_score, int direction)
|
||||||
|
{
|
||||||
|
return pico_protocol_generic_loop(&proto_rr_datalink, loop_score, direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pico_protocol_network_loop(int loop_score, int direction)
|
||||||
|
{
|
||||||
|
return pico_protocol_generic_loop(&proto_rr_network, loop_score, direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pico_protocol_transport_loop(int loop_score, int direction)
|
||||||
|
{
|
||||||
|
return pico_protocol_generic_loop(&proto_rr_transport, loop_score, direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pico_protocol_socket_loop(int loop_score, int direction)
|
||||||
|
{
|
||||||
|
return pico_protocol_generic_loop(&proto_rr_socket, loop_score, direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pico_protocols_loop(int loop_score)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
loop_score = pico_protocol_datalink_loop(loop_score);
|
||||||
|
loop_score = pico_protocol_network_loop(loop_score);
|
||||||
|
loop_score = pico_protocol_transport_loop(loop_score);
|
||||||
|
loop_score = pico_protocol_socket_loop(loop_score);
|
||||||
|
*/
|
||||||
|
return loop_score;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void proto_layer_rr_reset(struct pico_proto_rr *rr)
|
||||||
|
{
|
||||||
|
rr->node_in = NULL;
|
||||||
|
rr->node_out = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pico_protocol_init(struct pico_protocol *p)
|
||||||
|
{
|
||||||
|
struct pico_tree *tree = NULL;
|
||||||
|
struct pico_proto_rr *proto = NULL;
|
||||||
|
|
||||||
|
if (!p)
|
||||||
|
return;
|
||||||
|
|
||||||
|
p->hash = pico_hash(p->name, (uint32_t)strlen(p->name));
|
||||||
|
switch (p->layer) {
|
||||||
|
case PICO_LAYER_DATALINK:
|
||||||
|
tree = &Datalink_proto_tree;
|
||||||
|
proto = &proto_rr_datalink;
|
||||||
|
break;
|
||||||
|
case PICO_LAYER_NETWORK:
|
||||||
|
tree = &Network_proto_tree;
|
||||||
|
proto = &proto_rr_network;
|
||||||
|
break;
|
||||||
|
case PICO_LAYER_TRANSPORT:
|
||||||
|
tree = &Transport_proto_tree;
|
||||||
|
proto = &proto_rr_transport;
|
||||||
|
break;
|
||||||
|
case PICO_LAYER_SOCKET:
|
||||||
|
tree = &Socket_proto_tree;
|
||||||
|
proto = &proto_rr_socket;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dbg("Unknown protocol: %s (layer: %d)\n", p->name, p->layer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pico_tree_insert(tree, p)) {
|
||||||
|
dbg("Failed to insert protocol %s\n", p->name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
proto_layer_rr_reset(proto);
|
||||||
|
dbg("Protocol %s registered (layer: %d).\n", p->name, p->layer);
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,962 @@
|
||||||
|
/*********************************************************************
|
||||||
|
PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved.
|
||||||
|
See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage.
|
||||||
|
|
||||||
|
.
|
||||||
|
|
||||||
|
Authors: Daniele Lacamera
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "pico_config.h"
|
||||||
|
#include "pico_frame.h"
|
||||||
|
#include "pico_device.h"
|
||||||
|
#include "pico_protocol.h"
|
||||||
|
#include "pico_stack.h"
|
||||||
|
#include "pico_addressing.h"
|
||||||
|
#include "pico_dns_client.h"
|
||||||
|
|
||||||
|
#include "pico_6lowpan_ll.h"
|
||||||
|
#include "pico_ethernet.h"
|
||||||
|
#include "pico_6lowpan.h"
|
||||||
|
#include "pico_olsr.h"
|
||||||
|
#include "pico_aodv.h"
|
||||||
|
#include "pico_eth.h"
|
||||||
|
#include "pico_arp.h"
|
||||||
|
#include "pico_ipv4.h"
|
||||||
|
#include "pico_ipv6.h"
|
||||||
|
#include "pico_icmp4.h"
|
||||||
|
#include "pico_icmp6.h"
|
||||||
|
#include "pico_igmp.h"
|
||||||
|
#include "pico_udp.h"
|
||||||
|
#include "pico_tcp.h"
|
||||||
|
#include "pico_socket.h"
|
||||||
|
#include "heap.h"
|
||||||
|
|
||||||
|
/* Mockables */
|
||||||
|
#if defined UNIT_TEST
|
||||||
|
# define MOCKABLE __attribute__((weak))
|
||||||
|
#else
|
||||||
|
# define MOCKABLE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
volatile pico_time pico_tick;
|
||||||
|
volatile pico_err_t pico_err;
|
||||||
|
|
||||||
|
static uint32_t _rand_seed;
|
||||||
|
|
||||||
|
void WEAK pico_rand_feed(uint32_t feed)
|
||||||
|
{
|
||||||
|
if (!feed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_rand_seed *= 1664525;
|
||||||
|
_rand_seed += 1013904223;
|
||||||
|
_rand_seed ^= ~(feed);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t WEAK pico_rand(void)
|
||||||
|
{
|
||||||
|
pico_rand_feed((uint32_t)pico_tick);
|
||||||
|
return _rand_seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pico_to_lowercase(char *str)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
if (!str)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while(str[i]) {
|
||||||
|
if ((str[i] <= 'Z') && (str[i] >= 'A'))
|
||||||
|
str[i] = (char) (str[i] - (char)('A' - 'a'));
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTIFICATIONS: distributed notifications for stack internal errors.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int pico_notify_socket_unreachable(struct pico_frame *f)
|
||||||
|
{
|
||||||
|
if (0) {}
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_ICMP4
|
||||||
|
else if (IS_IPV4(f)) {
|
||||||
|
pico_icmp4_port_unreachable(f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef PICO_SUPPORT_ICMP6
|
||||||
|
else if (IS_IPV6(f)) {
|
||||||
|
pico_icmp6_port_unreachable(f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pico_notify_proto_unreachable(struct pico_frame *f)
|
||||||
|
{
|
||||||
|
if (0) {}
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_ICMP4
|
||||||
|
else if (IS_IPV4(f)) {
|
||||||
|
pico_icmp4_proto_unreachable(f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef PICO_SUPPORT_ICMP6
|
||||||
|
else if (IS_IPV6(f)) {
|
||||||
|
pico_icmp6_proto_unreachable(f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pico_notify_dest_unreachable(struct pico_frame *f)
|
||||||
|
{
|
||||||
|
if (0) {}
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_ICMP4
|
||||||
|
else if (IS_IPV4(f)) {
|
||||||
|
pico_icmp4_dest_unreachable(f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef PICO_SUPPORT_ICMP6
|
||||||
|
else if (IS_IPV6(f)) {
|
||||||
|
pico_icmp6_dest_unreachable(f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pico_notify_ttl_expired(struct pico_frame *f)
|
||||||
|
{
|
||||||
|
if (0) {}
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_ICMP4
|
||||||
|
else if (IS_IPV4(f)) {
|
||||||
|
pico_icmp4_ttl_expired(f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef PICO_SUPPORT_ICMP6
|
||||||
|
else if (IS_IPV6(f)) {
|
||||||
|
pico_icmp6_ttl_expired(f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pico_notify_frag_expired(struct pico_frame *f)
|
||||||
|
{
|
||||||
|
if (0) {}
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_ICMP4
|
||||||
|
else if (IS_IPV4(f)) {
|
||||||
|
pico_icmp4_frag_expired(f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef PICO_SUPPORT_ICMP6
|
||||||
|
else if (IS_IPV6(f)) {
|
||||||
|
pico_icmp6_frag_expired(f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pico_notify_pkt_too_big(struct pico_frame *f)
|
||||||
|
{
|
||||||
|
if (0) {}
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_ICMP4
|
||||||
|
else if (IS_IPV4(f)) {
|
||||||
|
pico_icmp4_mtu_exceeded(f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef PICO_SUPPORT_ICMP6
|
||||||
|
else if (IS_IPV6(f)) {
|
||||||
|
pico_icmp6_pkt_too_big(f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* TRANSPORT LAYER
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
MOCKABLE int32_t pico_transport_receive(struct pico_frame *f, uint8_t proto)
|
||||||
|
{
|
||||||
|
int32_t ret = -1;
|
||||||
|
switch (proto) {
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_ICMP4
|
||||||
|
case PICO_PROTO_ICMP4:
|
||||||
|
ret = pico_enqueue(pico_proto_icmp4.q_in, f);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_ICMP6
|
||||||
|
case PICO_PROTO_ICMP6:
|
||||||
|
ret = pico_enqueue(pico_proto_icmp6.q_in, f);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(PICO_SUPPORT_IGMP) && defined(PICO_SUPPORT_MCAST)
|
||||||
|
case PICO_PROTO_IGMP:
|
||||||
|
ret = pico_enqueue(pico_proto_igmp.q_in, f);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_UDP
|
||||||
|
case PICO_PROTO_UDP:
|
||||||
|
ret = pico_enqueue(pico_proto_udp.q_in, f);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_TCP
|
||||||
|
case PICO_PROTO_TCP:
|
||||||
|
ret = pico_enqueue(pico_proto_tcp.q_in, f);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Protocol not available */
|
||||||
|
dbg("pkt: no such protocol (%d)\n", proto);
|
||||||
|
pico_notify_proto_unreachable(f);
|
||||||
|
pico_frame_discard(f);
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* NETWORK LAYER
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
MOCKABLE int32_t pico_network_receive(struct pico_frame *f)
|
||||||
|
{
|
||||||
|
if (0) {}
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_IPV4
|
||||||
|
else if (IS_IPV4(f)) {
|
||||||
|
pico_enqueue(pico_proto_ipv4.q_in, f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef PICO_SUPPORT_IPV6
|
||||||
|
else if (IS_IPV6(f)) {
|
||||||
|
pico_enqueue(pico_proto_ipv6.q_in, f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else {
|
||||||
|
dbg("Network not found.\n");
|
||||||
|
pico_frame_discard(f);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return (int32_t)f->buffer_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Interface towards socket for frame sending
|
||||||
|
int32_t pico_network_send(struct pico_frame *f)
|
||||||
|
{
|
||||||
|
if (!f || !f->sock || !f->sock->net) {
|
||||||
|
pico_frame_discard(f);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return f->sock->net->push(f->sock->net, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pico_source_is_local(struct pico_frame *f)
|
||||||
|
{
|
||||||
|
if (0) { }
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_IPV4
|
||||||
|
else if (IS_IPV4(f)) {
|
||||||
|
struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)f->net_hdr;
|
||||||
|
if (hdr->src.addr == PICO_IPV4_INADDR_ANY)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (pico_ipv4_link_find(&hdr->src))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef PICO_SUPPORT_IPV6
|
||||||
|
else if (IS_IPV6(f)) {
|
||||||
|
struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr;
|
||||||
|
if (pico_ipv6_is_unspecified(hdr->src.addr) || pico_ipv6_link_find(&hdr->src))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pico_store_network_origin(void *src, struct pico_frame *f)
|
||||||
|
{
|
||||||
|
#ifdef PICO_SUPPORT_IPV4
|
||||||
|
struct pico_ip4 *ip4;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_IPV6
|
||||||
|
struct pico_ip6 *ip6;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_IPV4
|
||||||
|
if (IS_IPV4(f)) {
|
||||||
|
struct pico_ipv4_hdr *hdr;
|
||||||
|
hdr = (struct pico_ipv4_hdr *) f->net_hdr;
|
||||||
|
ip4 = (struct pico_ip4 *) src;
|
||||||
|
ip4->addr = hdr->src.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#ifdef PICO_SUPPORT_IPV6
|
||||||
|
if (IS_IPV6(f)) {
|
||||||
|
struct pico_ipv6_hdr *hdr;
|
||||||
|
hdr = (struct pico_ipv6_hdr *) f->net_hdr;
|
||||||
|
ip6 = (struct pico_ip6 *) src;
|
||||||
|
memcpy(ip6->addr, hdr->src.addr, PICO_SIZE_IP6);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int pico_address_compare(union pico_address *a, union pico_address *b, uint16_t proto)
|
||||||
|
{
|
||||||
|
#ifdef PICO_SUPPORT_IPV6
|
||||||
|
if (proto == PICO_PROTO_IPV6) {
|
||||||
|
return pico_ipv6_compare(&a->ip6, &b->ip6);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#ifdef PICO_SUPPORT_IPV4
|
||||||
|
if (proto == PICO_PROTO_IPV4) {
|
||||||
|
return pico_ipv4_compare(&a->ip4, &b->ip4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int pico_frame_dst_is_unicast(struct pico_frame *f)
|
||||||
|
{
|
||||||
|
if (0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_IPV4
|
||||||
|
if (IS_IPV4(f)) {
|
||||||
|
struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)f->net_hdr;
|
||||||
|
if (pico_ipv4_is_multicast(hdr->dst.addr) || pico_ipv4_is_broadcast(hdr->dst.addr))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_IPV6
|
||||||
|
if (IS_IPV6(f)) {
|
||||||
|
struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr;
|
||||||
|
if (pico_ipv6_is_multicast(hdr->dst.addr) || pico_ipv6_is_unspecified(hdr->dst.addr))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* DATALINK LAYER
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
int pico_datalink_receive(struct pico_frame *f)
|
||||||
|
{
|
||||||
|
if (f->dev->eth) {
|
||||||
|
/* If device has stack with datalink-layer pass frame through it */
|
||||||
|
switch (f->dev->mode) {
|
||||||
|
#ifdef PICO_SUPPORT_802154
|
||||||
|
case LL_MODE_IEEE802154:
|
||||||
|
f->datalink_hdr = f->buffer;
|
||||||
|
return pico_enqueue(pico_proto_6lowpan_ll.q_in, f);
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
#ifdef PICO_SUPPORT_ETH
|
||||||
|
f->datalink_hdr = f->buffer;
|
||||||
|
return pico_enqueue(pico_proto_ethernet.q_in,f);
|
||||||
|
#else
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* If device handles raw IP-frames send it straight to network-layer */
|
||||||
|
f->net_hdr = f->buffer;
|
||||||
|
pico_network_receive(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOCKABLE int pico_datalink_send(struct pico_frame *f)
|
||||||
|
{
|
||||||
|
if (f->dev->eth) {
|
||||||
|
switch (f->dev->mode) {
|
||||||
|
#ifdef PICO_SUPPORT_802154
|
||||||
|
case LL_MODE_IEEE802154:
|
||||||
|
return pico_enqueue(pico_proto_6lowpan.q_out, f);
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
#ifdef PICO_SUPPORT_ETH
|
||||||
|
return pico_enqueue(pico_proto_ethernet.q_out, f);
|
||||||
|
#else
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* non-ethernet: no post-processing needed */
|
||||||
|
return pico_sendto_dev(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* PHYSICAL LAYER
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
struct pico_frame *pico_stack_recv_new_frame(struct pico_device *dev, uint8_t *buffer, uint32_t len)
|
||||||
|
{
|
||||||
|
struct pico_frame *f;
|
||||||
|
if (len == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
f = pico_frame_alloc(len);
|
||||||
|
if (!f)
|
||||||
|
{
|
||||||
|
dbg("Cannot alloc incoming frame!\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Association to the device that just received the frame. */
|
||||||
|
f->dev = dev;
|
||||||
|
|
||||||
|
/* Setup the start pointer, length. */
|
||||||
|
f->start = f->buffer;
|
||||||
|
f->len = f->buffer_len;
|
||||||
|
if (f->len > 8) {
|
||||||
|
uint32_t rand, mid_frame = (f->buffer_len >> 2) << 1;
|
||||||
|
mid_frame -= (mid_frame % 4);
|
||||||
|
memcpy(&rand, f->buffer + mid_frame, sizeof(uint32_t));
|
||||||
|
pico_rand_feed(rand);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(f->buffer, buffer, len);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LOWEST LEVEL: interface towards devices. */
|
||||||
|
/* Device driver will call this function which returns immediately.
|
||||||
|
* Incoming packet will be processed later on in the dev loop.
|
||||||
|
*/
|
||||||
|
int32_t pico_stack_recv(struct pico_device *dev, uint8_t *buffer, uint32_t len)
|
||||||
|
{
|
||||||
|
struct pico_frame *f = pico_stack_recv_new_frame (dev, buffer, len);
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
if (!f)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ret = pico_enqueue(dev->q_in, f);
|
||||||
|
if (ret <= 0) {
|
||||||
|
pico_frame_discard(f);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t _pico_stack_recv_zerocopy(struct pico_device *dev, uint8_t *buffer, uint32_t len, int ext_buffer, void (*notify_free)(uint8_t *))
|
||||||
|
{
|
||||||
|
struct pico_frame *f;
|
||||||
|
int ret;
|
||||||
|
if (len == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
f = pico_frame_alloc_skeleton(len, ext_buffer);
|
||||||
|
if (!f)
|
||||||
|
{
|
||||||
|
dbg("Cannot alloc incoming frame!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pico_frame_skeleton_set_buffer(f, buffer) < 0)
|
||||||
|
{
|
||||||
|
dbg("Invalid zero-copy buffer!\n");
|
||||||
|
PICO_FREE(f->usage_count);
|
||||||
|
PICO_FREE(f);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notify_free) {
|
||||||
|
f->notify_free = notify_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
f->dev = dev;
|
||||||
|
ret = pico_enqueue(dev->q_in, f);
|
||||||
|
if (ret <= 0) {
|
||||||
|
pico_frame_discard(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t pico_stack_recv_zerocopy(struct pico_device *dev, uint8_t *buffer, uint32_t len)
|
||||||
|
{
|
||||||
|
return _pico_stack_recv_zerocopy(dev, buffer, len, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t pico_stack_recv_zerocopy_ext_buffer(struct pico_device *dev, uint8_t *buffer, uint32_t len)
|
||||||
|
{
|
||||||
|
return _pico_stack_recv_zerocopy(dev, buffer, len, 1, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t pico_stack_recv_zerocopy_ext_buffer_notify(struct pico_device *dev, uint8_t *buffer, uint32_t len, void (*notify_free)(uint8_t *buffer))
|
||||||
|
{
|
||||||
|
return _pico_stack_recv_zerocopy(dev, buffer, len, 1, notify_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t pico_sendto_dev(struct pico_frame *f)
|
||||||
|
{
|
||||||
|
if (!f->dev) {
|
||||||
|
pico_frame_discard(f);
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
if (f->len > 8) {
|
||||||
|
uint32_t rand, mid_frame = (f->buffer_len >> 2) << 1;
|
||||||
|
mid_frame -= (mid_frame % 4);
|
||||||
|
memcpy(&rand, f->buffer + mid_frame, sizeof(uint32_t));
|
||||||
|
pico_rand_feed(rand);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pico_enqueue(f->dev->q_out, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pico_timer
|
||||||
|
{
|
||||||
|
void *arg;
|
||||||
|
void (*timer)(pico_time timestamp, void *arg);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static uint32_t tmr_id = 0u;
|
||||||
|
struct pico_timer_ref
|
||||||
|
{
|
||||||
|
pico_time expire;
|
||||||
|
uint32_t id;
|
||||||
|
uint32_t hash;
|
||||||
|
struct pico_timer *tmr;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct pico_timer_ref pico_timer_ref;
|
||||||
|
|
||||||
|
DECLARE_HEAP(pico_timer_ref, expire);
|
||||||
|
|
||||||
|
static heap_pico_timer_ref *Timers;
|
||||||
|
|
||||||
|
int32_t pico_seq_compare(uint32_t a, uint32_t b)
|
||||||
|
{
|
||||||
|
uint32_t thresh = ((uint32_t)(-1)) >> 1;
|
||||||
|
|
||||||
|
if (a > b) /* return positive number, if not wrapped */
|
||||||
|
{
|
||||||
|
if ((a - b) > thresh) /* b wrapped */
|
||||||
|
return -(int32_t)(b - a); /* b = very small, a = very big */
|
||||||
|
else
|
||||||
|
return (int32_t)(a - b); /* a = biggest, b = a bit smaller */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a < b) /* return negative number, if not wrapped */
|
||||||
|
{
|
||||||
|
if ((b - a) > thresh) /* a wrapped */
|
||||||
|
return (int32_t)(a - b); /* a = very small, b = very big */
|
||||||
|
else
|
||||||
|
return -(int32_t)(b - a); /* b = biggest, a = a bit smaller */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pico_check_timers(void)
|
||||||
|
{
|
||||||
|
struct pico_timer *t;
|
||||||
|
struct pico_timer_ref tref_unused, *tref = heap_first(Timers);
|
||||||
|
pico_tick = PICO_TIME_MS();
|
||||||
|
while((tref) && (tref->expire < pico_tick)) {
|
||||||
|
t = tref->tmr;
|
||||||
|
if (t && t->timer)
|
||||||
|
t->timer(pico_tick, t->arg);
|
||||||
|
|
||||||
|
if (t)
|
||||||
|
{
|
||||||
|
PICO_FREE(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
heap_peek(Timers, &tref_unused);
|
||||||
|
tref = heap_first(Timers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MOCKABLE pico_timer_cancel(uint32_t id)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
struct pico_timer_ref *tref;
|
||||||
|
if (id == 0u)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 1; i <= Timers->n; i++) {
|
||||||
|
tref = heap_get_element(Timers, i);
|
||||||
|
if (tref->id == id) {
|
||||||
|
if (tref->tmr)
|
||||||
|
{
|
||||||
|
PICO_FREE(tref->tmr);
|
||||||
|
tref->tmr = NULL;
|
||||||
|
tref->id = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pico_timer_cancel_hashed(uint32_t hash)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
struct pico_timer_ref *tref;
|
||||||
|
if (hash == 0u)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 1; i <= Timers->n; i++) {
|
||||||
|
tref = heap_get_element(Timers, i);
|
||||||
|
if (tref->hash == hash) {
|
||||||
|
if (tref->tmr)
|
||||||
|
{
|
||||||
|
PICO_FREE(tref->tmr);
|
||||||
|
tref->tmr = NULL;
|
||||||
|
tref[i].id = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PROTO_DEF_NR 11
|
||||||
|
#define PROTO_DEF_AVG_NR 4
|
||||||
|
#define PROTO_DEF_SCORE 32
|
||||||
|
#define PROTO_MIN_SCORE 32
|
||||||
|
#define PROTO_MAX_SCORE 128
|
||||||
|
#define PROTO_LAT_IND 3 /* latency indication 0-3 (lower is better latency performance), x1, x2, x4, x8 */
|
||||||
|
#define PROTO_MAX_LOOP (PROTO_MAX_SCORE << PROTO_LAT_IND) /* max global loop score, so per tick */
|
||||||
|
|
||||||
|
static int calc_score(int *score, int *index, int avg[][PROTO_DEF_AVG_NR], int *ret)
|
||||||
|
{
|
||||||
|
int temp, i, j, sum;
|
||||||
|
int max_total = PROTO_MAX_LOOP, total = 0;
|
||||||
|
|
||||||
|
/* dbg("USED SCORES> "); */
|
||||||
|
|
||||||
|
for (i = 0; i < PROTO_DEF_NR; i++) {
|
||||||
|
|
||||||
|
/* if used looped score */
|
||||||
|
if (ret[i] < score[i]) {
|
||||||
|
temp = score[i] - ret[i]; /* remaining loop score */
|
||||||
|
|
||||||
|
/* dbg("%3d - ",temp); */
|
||||||
|
|
||||||
|
if (index[i] >= PROTO_DEF_AVG_NR)
|
||||||
|
index[i] = 0; /* reset index */
|
||||||
|
|
||||||
|
j = index[i];
|
||||||
|
avg[i][j] = temp;
|
||||||
|
|
||||||
|
index[i]++;
|
||||||
|
|
||||||
|
if (ret[i] == 0 && ((score[i] * 2) <= PROTO_MAX_SCORE) && ((total + (score[i] * 2)) < max_total)) { /* used all loop score -> increase next score directly */
|
||||||
|
score[i] *= 2;
|
||||||
|
total += score[i];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sum = 0;
|
||||||
|
for (j = 0; j < PROTO_DEF_AVG_NR; j++)
|
||||||
|
sum += avg[i][j]; /* calculate sum */
|
||||||
|
|
||||||
|
sum /= 4; /* divide by 4 to get average used score */
|
||||||
|
|
||||||
|
/* criterion to increase next loop score */
|
||||||
|
if (sum > (score[i] - (score[i] / 4)) && ((score[i] * 2) <= PROTO_MAX_SCORE) && ((total + (score[i] / 2)) < max_total)) { /* > 3/4 */
|
||||||
|
score[i] *= 2; /* double loop score */
|
||||||
|
total += score[i];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* criterion to decrease next loop score */
|
||||||
|
if ((sum < (score[i] / 4)) && ((score[i] / 2) >= PROTO_MIN_SCORE)) { /* < 1/4 */
|
||||||
|
score[i] /= 2; /* half loop score */
|
||||||
|
total += score[i];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* also add non-changed scores */
|
||||||
|
total += score[i];
|
||||||
|
}
|
||||||
|
else if (ret[i] == score[i]) {
|
||||||
|
/* no used loop score - gradually decrease */
|
||||||
|
|
||||||
|
/* dbg("%3d - ",0); */
|
||||||
|
|
||||||
|
if (index[i] >= PROTO_DEF_AVG_NR)
|
||||||
|
index[i] = 0; /* reset index */
|
||||||
|
|
||||||
|
j = index[i];
|
||||||
|
avg[i][j] = 0;
|
||||||
|
|
||||||
|
index[i]++;
|
||||||
|
|
||||||
|
sum = 0;
|
||||||
|
for (j = 0; j < PROTO_DEF_AVG_NR; j++)
|
||||||
|
sum += avg[i][j]; /* calculate sum */
|
||||||
|
|
||||||
|
sum /= 2; /* divide by 4 to get average used score */
|
||||||
|
|
||||||
|
if ((sum == 0) && ((score[i] / 2) >= PROTO_MIN_SCORE)) {
|
||||||
|
score[i] /= 2; /* half loop score */
|
||||||
|
total += score[i];
|
||||||
|
for (j = 0; j < PROTO_DEF_AVG_NR; j++)
|
||||||
|
avg[i][j] = score[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* dbg("\n"); */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pico_stack_tick(void)
|
||||||
|
{
|
||||||
|
static int score[PROTO_DEF_NR] = {
|
||||||
|
PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE
|
||||||
|
};
|
||||||
|
static int index[PROTO_DEF_NR] = {
|
||||||
|
0, 0, 0, 0, 0, 0
|
||||||
|
};
|
||||||
|
static int avg[PROTO_DEF_NR][PROTO_DEF_AVG_NR];
|
||||||
|
static int ret[PROTO_DEF_NR] = {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
pico_check_timers();
|
||||||
|
|
||||||
|
/* dbg("LOOP_SCORES> %3d - %3d - %3d - %3d - %3d - %3d - %3d - %3d - %3d - %3d - %3d\n",score[0],score[1],score[2],score[3],score[4],score[5],score[6],score[7],score[8],score[9],score[10]); */
|
||||||
|
|
||||||
|
/* score = pico_protocols_loop(100); */
|
||||||
|
|
||||||
|
ret[0] = pico_devices_loop(score[0], PICO_LOOP_DIR_IN);
|
||||||
|
pico_rand_feed((uint32_t)ret[0]);
|
||||||
|
|
||||||
|
ret[1] = pico_protocol_datalink_loop(score[1], PICO_LOOP_DIR_IN);
|
||||||
|
pico_rand_feed((uint32_t)ret[1]);
|
||||||
|
|
||||||
|
ret[2] = pico_protocol_network_loop(score[2], PICO_LOOP_DIR_IN);
|
||||||
|
pico_rand_feed((uint32_t)ret[2]);
|
||||||
|
|
||||||
|
ret[3] = pico_protocol_transport_loop(score[3], PICO_LOOP_DIR_IN);
|
||||||
|
pico_rand_feed((uint32_t)ret[3]);
|
||||||
|
|
||||||
|
|
||||||
|
ret[5] = score[5];
|
||||||
|
#if defined (PICO_SUPPORT_IPV4) || defined (PICO_SUPPORT_IPV6)
|
||||||
|
#if defined (PICO_SUPPORT_TCP) || defined (PICO_SUPPORT_UDP)
|
||||||
|
ret[5] = pico_sockets_loop(score[5]); /* swapped */
|
||||||
|
pico_rand_feed((uint32_t)ret[5]);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ret[4] = pico_protocol_socket_loop(score[4], PICO_LOOP_DIR_IN);
|
||||||
|
pico_rand_feed((uint32_t)ret[4]);
|
||||||
|
|
||||||
|
|
||||||
|
ret[6] = pico_protocol_socket_loop(score[6], PICO_LOOP_DIR_OUT);
|
||||||
|
pico_rand_feed((uint32_t)ret[6]);
|
||||||
|
|
||||||
|
ret[7] = pico_protocol_transport_loop(score[7], PICO_LOOP_DIR_OUT);
|
||||||
|
pico_rand_feed((uint32_t)ret[7]);
|
||||||
|
|
||||||
|
ret[8] = pico_protocol_network_loop(score[8], PICO_LOOP_DIR_OUT);
|
||||||
|
pico_rand_feed((uint32_t)ret[8]);
|
||||||
|
|
||||||
|
ret[9] = pico_protocol_datalink_loop(score[9], PICO_LOOP_DIR_OUT);
|
||||||
|
pico_rand_feed((uint32_t)ret[9]);
|
||||||
|
|
||||||
|
ret[10] = pico_devices_loop(score[10], PICO_LOOP_DIR_OUT);
|
||||||
|
pico_rand_feed((uint32_t)ret[10]);
|
||||||
|
|
||||||
|
/* calculate new loop scores for next iteration */
|
||||||
|
calc_score(score, index, (int (*)[])avg, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pico_stack_loop(void)
|
||||||
|
{
|
||||||
|
while(1) {
|
||||||
|
pico_stack_tick();
|
||||||
|
PICO_IDLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
pico_timer_ref_add(pico_time expire, struct pico_timer *t, uint32_t id, uint32_t hash)
|
||||||
|
{
|
||||||
|
struct pico_timer_ref tref;
|
||||||
|
|
||||||
|
tref.expire = PICO_TIME_MS() + expire;
|
||||||
|
tref.tmr = t;
|
||||||
|
tref.id = id;
|
||||||
|
tref.hash = hash;
|
||||||
|
|
||||||
|
if (heap_insert(Timers, &tref) < 0) {
|
||||||
|
dbg("Error: failed to insert timer(ID %u) into heap\n", id);
|
||||||
|
PICO_FREE(t);
|
||||||
|
pico_err = PICO_ERR_ENOMEM;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (Timers->n > PICO_MAX_TIMERS) {
|
||||||
|
dbg("Warning: I have %d timers\n", (int)Timers->n);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tref.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct pico_timer *
|
||||||
|
pico_timer_create(void (*timer)(pico_time, void *), void *arg)
|
||||||
|
{
|
||||||
|
struct pico_timer *t = PICO_ZALLOC(sizeof(struct pico_timer));
|
||||||
|
|
||||||
|
if (!t) {
|
||||||
|
pico_err = PICO_ERR_ENOMEM;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
t->arg = arg;
|
||||||
|
t->timer = timer;
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOCKABLE uint32_t pico_timer_add(pico_time expire, void (*timer)(pico_time, void *), void *arg)
|
||||||
|
{
|
||||||
|
struct pico_timer *t = pico_timer_create(timer, arg);
|
||||||
|
|
||||||
|
/* zero is guard for timers */
|
||||||
|
if (tmr_id == 0u) {
|
||||||
|
tmr_id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!t)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return pico_timer_ref_add(expire, t, tmr_id++, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pico_timer_add_hashed(pico_time expire, void (*timer)(pico_time, void *), void *arg, uint32_t hash)
|
||||||
|
{
|
||||||
|
struct pico_timer *t = pico_timer_create(timer, arg);
|
||||||
|
|
||||||
|
/* zero is guard for timers */
|
||||||
|
if (tmr_id == 0u) {
|
||||||
|
tmr_id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!t)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return pico_timer_ref_add(expire, t, tmr_id++, hash);
|
||||||
|
} /* Static path count: 4 */
|
||||||
|
|
||||||
|
int MOCKABLE pico_stack_init(void)
|
||||||
|
{
|
||||||
|
#ifdef PICO_SUPPORT_ETH
|
||||||
|
pico_protocol_init(&pico_proto_ethernet);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_6LOWPAN
|
||||||
|
pico_protocol_init(&pico_proto_6lowpan);
|
||||||
|
pico_protocol_init(&pico_proto_6lowpan_ll);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_IPV4
|
||||||
|
pico_protocol_init(&pico_proto_ipv4);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_IPV6
|
||||||
|
pico_protocol_init(&pico_proto_ipv6);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_ICMP4
|
||||||
|
pico_protocol_init(&pico_proto_icmp4);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_ICMP6
|
||||||
|
pico_protocol_init(&pico_proto_icmp6);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PICO_SUPPORT_IGMP) && defined(PICO_SUPPORT_MCAST)
|
||||||
|
pico_protocol_init(&pico_proto_igmp);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_UDP
|
||||||
|
pico_protocol_init(&pico_proto_udp);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_TCP
|
||||||
|
pico_protocol_init(&pico_proto_tcp);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_DNS_CLIENT
|
||||||
|
pico_dns_client_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pico_rand_feed(123456);
|
||||||
|
|
||||||
|
/* Initialize timer heap */
|
||||||
|
Timers = heap_init();
|
||||||
|
if (!Timers)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
#if ((defined PICO_SUPPORT_IPV4) && (defined PICO_SUPPORT_ETH))
|
||||||
|
/* Initialize ARP module */
|
||||||
|
pico_arp_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_IPV6
|
||||||
|
/* Initialize Neighbor discovery module */
|
||||||
|
pico_ipv6_nd_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_OLSR
|
||||||
|
pico_olsr_init();
|
||||||
|
#endif
|
||||||
|
#ifdef PICO_SUPPORT_AODV
|
||||||
|
pico_aodv_init();
|
||||||
|
#endif
|
||||||
|
#ifdef PICO_SUPPORT_6LOWPAN
|
||||||
|
if (pico_6lowpan_init())
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
pico_stack_tick();
|
||||||
|
pico_stack_tick();
|
||||||
|
pico_stack_tick();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,565 @@
|
||||||
|
/*********************************************************************
|
||||||
|
PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved.
|
||||||
|
See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage.
|
||||||
|
|
||||||
|
Author: Andrei Carp <andrei.carp@tass.be>
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#include "pico_tree.h"
|
||||||
|
#include "pico_config.h"
|
||||||
|
#include "pico_protocol.h"
|
||||||
|
#include "pico_mm.h"
|
||||||
|
|
||||||
|
#define RED 0
|
||||||
|
#define BLACK 1
|
||||||
|
|
||||||
|
/* By default the null leafs are black */
|
||||||
|
struct pico_tree_node LEAF = {
|
||||||
|
NULL, /* key */
|
||||||
|
&LEAF, &LEAF, &LEAF, /* parent, left,right */
|
||||||
|
BLACK, /* color */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IS_LEAF(x) (x == &LEAF)
|
||||||
|
#define IS_NOT_LEAF(x) (x != &LEAF)
|
||||||
|
#define INIT_LEAF (&LEAF)
|
||||||
|
|
||||||
|
#define AM_I_LEFT_CHILD(x) (x == x->parent->leftChild)
|
||||||
|
#define AM_I_RIGHT_CHILD(x) (x == x->parent->rightChild)
|
||||||
|
|
||||||
|
#define PARENT(x) (x->parent)
|
||||||
|
#define GRANPA(x) (x->parent->parent)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Functions
|
||||||
|
*/
|
||||||
|
static struct pico_tree_node *create_node(struct pico_tree *tree, void *key, uint8_t allocator);
|
||||||
|
static void rotateToLeft(struct pico_tree*tree, struct pico_tree_node*node);
|
||||||
|
static void rotateToRight(struct pico_tree*root, struct pico_tree_node*node);
|
||||||
|
static void fix_insert_collisions(struct pico_tree*tree, struct pico_tree_node*node);
|
||||||
|
static void fix_delete_collisions(struct pico_tree*tree, struct pico_tree_node *node);
|
||||||
|
static void switchNodes(struct pico_tree*tree, struct pico_tree_node*nodeA, struct pico_tree_node*nodeB);
|
||||||
|
void *pico_tree_insert_implementation(struct pico_tree *tree, void *key, uint8_t allocator);
|
||||||
|
void *pico_tree_delete_implementation(struct pico_tree *tree, void *key, uint8_t allocator);
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_MM
|
||||||
|
/* The memory manager also uses the pico_tree to keep track of all the different slab sizes it has.
|
||||||
|
* These nodes should be placed in the manager page which is in a different memory region then the nodes
|
||||||
|
* which are used for the pico stack in general.
|
||||||
|
* Therefore the following 2 functions are created so that pico_tree can use them to to put these nodes
|
||||||
|
* into the correct memory regions.
|
||||||
|
* If pico_tree_insert is called from the memory manager module, then create_node should use
|
||||||
|
* pico_mem_page0_zalloc to create a node. The same for pico_tree_delete.
|
||||||
|
*/
|
||||||
|
extern void*pico_mem_page0_zalloc(size_t len);
|
||||||
|
extern void pico_mem_page0_free(void*ptr);
|
||||||
|
#endif /* PICO_SUPPORT_MM */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exported functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct pico_tree_node *pico_tree_firstNode(struct pico_tree_node *node)
|
||||||
|
{
|
||||||
|
while(IS_NOT_LEAF(node->leftChild))
|
||||||
|
node = node->leftChild;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pico_tree_node *pico_tree_lastNode(struct pico_tree_node *node)
|
||||||
|
{
|
||||||
|
while(IS_NOT_LEAF(node->rightChild))
|
||||||
|
node = node->rightChild;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pico_tree_node *pico_tree_next(struct pico_tree_node *node)
|
||||||
|
{
|
||||||
|
if (!node)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if(IS_NOT_LEAF(node->rightChild))
|
||||||
|
{
|
||||||
|
node = node->rightChild;
|
||||||
|
while(IS_NOT_LEAF(node->leftChild))
|
||||||
|
node = node->leftChild;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (IS_NOT_LEAF(node->parent) && AM_I_LEFT_CHILD(node))
|
||||||
|
node = node->parent;
|
||||||
|
else {
|
||||||
|
while (IS_NOT_LEAF(node->parent) && AM_I_RIGHT_CHILD(node))
|
||||||
|
node = node->parent;
|
||||||
|
node = node->parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pico_tree_node *pico_tree_prev(struct pico_tree_node *node)
|
||||||
|
{
|
||||||
|
if (IS_NOT_LEAF(node->leftChild)) {
|
||||||
|
node = node->leftChild;
|
||||||
|
while (IS_NOT_LEAF(node->rightChild))
|
||||||
|
node = node->rightChild;
|
||||||
|
} else {
|
||||||
|
if (IS_NOT_LEAF(node->parent) && AM_I_RIGHT_CHILD(node))
|
||||||
|
node = node->parent;
|
||||||
|
else {
|
||||||
|
while (IS_NOT_LEAF(node) && AM_I_LEFT_CHILD(node))
|
||||||
|
node = node->parent;
|
||||||
|
node = node->parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The memory manager also uses the pico_tree to keep track of all the different slab sizes it has.
|
||||||
|
* These nodes should be placed in the manager page which is in a different memory region then the nodes
|
||||||
|
* which are used for the pico stack in general.
|
||||||
|
* Therefore the following wrapper for pico_tree_insert is created.
|
||||||
|
* The actual implementation can be found in pico_tree_insert_implementation.
|
||||||
|
*/
|
||||||
|
void *pico_tree_insert(struct pico_tree *tree, void *key)
|
||||||
|
{
|
||||||
|
return pico_tree_insert_implementation(tree, key, USE_PICO_ZALLOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pico_tree_insert_node(struct pico_tree *tree, struct pico_tree_node *insert)
|
||||||
|
{
|
||||||
|
struct pico_tree_node *temp = tree->root;
|
||||||
|
struct pico_tree_node *last_node = INIT_LEAF;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
/* search for the place to insert the new node */
|
||||||
|
while(IS_NOT_LEAF(temp))
|
||||||
|
{
|
||||||
|
last_node = temp;
|
||||||
|
result = tree->compare(insert->keyValue, temp->keyValue);
|
||||||
|
|
||||||
|
temp = (result < 0) ? (temp->leftChild) : (temp->rightChild);
|
||||||
|
}
|
||||||
|
/* make the needed connections */
|
||||||
|
insert->parent = last_node;
|
||||||
|
|
||||||
|
if(IS_LEAF(last_node))
|
||||||
|
tree->root = insert;
|
||||||
|
else{
|
||||||
|
result = tree->compare(insert->keyValue, last_node->keyValue);
|
||||||
|
if(result < 0)
|
||||||
|
last_node->leftChild = insert;
|
||||||
|
else
|
||||||
|
last_node->rightChild = insert;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *pico_tree_insert_implementation(struct pico_tree *tree, void *key, uint8_t allocator)
|
||||||
|
{
|
||||||
|
struct pico_tree_node *insert;
|
||||||
|
void *LocalKey;
|
||||||
|
|
||||||
|
LocalKey = (IS_NOT_LEAF(tree->root) ? pico_tree_findKey(tree, key) : NULL);
|
||||||
|
|
||||||
|
/* if node already in, bail out */
|
||||||
|
if(LocalKey) {
|
||||||
|
pico_err = PICO_ERR_EEXIST;
|
||||||
|
return LocalKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
insert = create_node(tree, key, allocator);
|
||||||
|
|
||||||
|
if(!insert)
|
||||||
|
{
|
||||||
|
pico_err = PICO_ERR_ENOMEM;
|
||||||
|
/* to let the user know that it couldn't insert */
|
||||||
|
return (void *)&LEAF;
|
||||||
|
}
|
||||||
|
|
||||||
|
pico_tree_insert_node(tree, insert);
|
||||||
|
|
||||||
|
/* fix colour issues */
|
||||||
|
fix_insert_collisions(tree, insert);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pico_tree_node *pico_tree_findNode(struct pico_tree *tree, void *key)
|
||||||
|
{
|
||||||
|
struct pico_tree_node *found;
|
||||||
|
|
||||||
|
found = tree->root;
|
||||||
|
|
||||||
|
while(IS_NOT_LEAF(found))
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
result = tree->compare(found->keyValue, key);
|
||||||
|
if(result == 0)
|
||||||
|
return found;
|
||||||
|
else if(result < 0)
|
||||||
|
found = found->rightChild;
|
||||||
|
else
|
||||||
|
found = found->leftChild;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *pico_tree_findKey(struct pico_tree *tree, void *key)
|
||||||
|
{
|
||||||
|
struct pico_tree_node *found;
|
||||||
|
|
||||||
|
found = pico_tree_findNode(tree, key);
|
||||||
|
if (found == NULL)
|
||||||
|
return NULL;
|
||||||
|
return found->keyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *pico_tree_first(struct pico_tree *tree)
|
||||||
|
{
|
||||||
|
return pico_tree_firstNode(tree->root)->keyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *pico_tree_last(struct pico_tree *tree)
|
||||||
|
{
|
||||||
|
return pico_tree_lastNode(tree->root)->keyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t pico_tree_delete_node(struct pico_tree *tree, struct pico_tree_node *d, struct pico_tree_node **temp)
|
||||||
|
{
|
||||||
|
struct pico_tree_node *min;
|
||||||
|
struct pico_tree_node *ltemp = d;
|
||||||
|
uint8_t nodeColor;
|
||||||
|
min = pico_tree_firstNode(d->rightChild);
|
||||||
|
nodeColor = min->color;
|
||||||
|
|
||||||
|
*temp = min->rightChild;
|
||||||
|
if(min->parent == ltemp && IS_NOT_LEAF(*temp))
|
||||||
|
(*temp)->parent = min;
|
||||||
|
else{
|
||||||
|
switchNodes(tree, min, min->rightChild);
|
||||||
|
min->rightChild = ltemp->rightChild;
|
||||||
|
if(IS_NOT_LEAF(min->rightChild)) min->rightChild->parent = min;
|
||||||
|
}
|
||||||
|
|
||||||
|
switchNodes(tree, ltemp, min);
|
||||||
|
min->leftChild = ltemp->leftChild;
|
||||||
|
|
||||||
|
if(IS_NOT_LEAF(min->leftChild))
|
||||||
|
min->leftChild->parent = min;
|
||||||
|
|
||||||
|
min->color = ltemp->color;
|
||||||
|
return nodeColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t pico_tree_delete_check_switch(struct pico_tree *tree, struct pico_tree_node *delete, struct pico_tree_node **temp)
|
||||||
|
{
|
||||||
|
struct pico_tree_node *ltemp = delete;
|
||||||
|
uint8_t nodeColor = delete->color;
|
||||||
|
if(IS_LEAF(delete->leftChild))
|
||||||
|
{
|
||||||
|
*temp = ltemp->rightChild;
|
||||||
|
switchNodes(tree, ltemp, ltemp->rightChild);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(IS_LEAF(delete->rightChild))
|
||||||
|
{
|
||||||
|
struct pico_tree_node *_ltemp = delete;
|
||||||
|
*temp = _ltemp->leftChild;
|
||||||
|
switchNodes(tree, _ltemp, _ltemp->leftChild);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
nodeColor = pico_tree_delete_node(tree, delete, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeColor;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The memory manager also uses the pico_tree to keep track of all the different slab sizes it has.
|
||||||
|
* These nodes should be placed in the manager page which is in a different memory region then the nodes
|
||||||
|
* which are used for the pico stack in general.
|
||||||
|
* Therefore the following wrapper for pico_tree_delete is created.
|
||||||
|
* The actual implementation can be found in pico_tree_delete_implementation.
|
||||||
|
*/
|
||||||
|
void *pico_tree_delete(struct pico_tree *tree, void *key)
|
||||||
|
{
|
||||||
|
return pico_tree_delete_implementation(tree, key, USE_PICO_ZALLOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void if_nodecolor_black_fix_collisions(struct pico_tree *tree, struct pico_tree_node *temp, uint8_t nodeColor)
|
||||||
|
{
|
||||||
|
/* deleted node is black, this will mess up the black path property */
|
||||||
|
if(nodeColor == BLACK)
|
||||||
|
fix_delete_collisions(tree, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *pico_tree_delete_implementation(struct pico_tree *tree, void *key, uint8_t allocator)
|
||||||
|
{
|
||||||
|
struct pico_tree_node *temp;
|
||||||
|
uint8_t nodeColor; /* keeps the color of the node to be deleted */
|
||||||
|
void *lkey; /* keeps a copy of the key which will be removed */
|
||||||
|
struct pico_tree_node *delete; /* keeps a copy of the node to be extracted */
|
||||||
|
if (!key)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
delete = pico_tree_findNode(tree, key);
|
||||||
|
|
||||||
|
/* this key isn't in the tree, bail out */
|
||||||
|
if(!delete)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
lkey = delete->keyValue;
|
||||||
|
nodeColor = pico_tree_delete_check_switch(tree, delete, &temp);
|
||||||
|
|
||||||
|
if_nodecolor_black_fix_collisions(tree, temp, nodeColor);
|
||||||
|
|
||||||
|
if(allocator == USE_PICO_ZALLOC)
|
||||||
|
PICO_FREE(delete);
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_MM
|
||||||
|
else
|
||||||
|
pico_mem_page0_free(delete);
|
||||||
|
#endif
|
||||||
|
return lkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pico_tree_empty(struct pico_tree *tree)
|
||||||
|
{
|
||||||
|
return (!tree->root || IS_LEAF(tree->root));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Private functions
|
||||||
|
*/
|
||||||
|
static void rotateToLeft(struct pico_tree*tree, struct pico_tree_node*node)
|
||||||
|
{
|
||||||
|
struct pico_tree_node*temp;
|
||||||
|
|
||||||
|
temp = node->rightChild;
|
||||||
|
|
||||||
|
if(temp == &LEAF) return;
|
||||||
|
|
||||||
|
node->rightChild = temp->leftChild;
|
||||||
|
|
||||||
|
if(IS_NOT_LEAF(temp->leftChild))
|
||||||
|
temp->leftChild->parent = node;
|
||||||
|
|
||||||
|
temp->parent = node->parent;
|
||||||
|
|
||||||
|
if(IS_LEAF(node->parent))
|
||||||
|
tree->root = temp;
|
||||||
|
else
|
||||||
|
if(node == node->parent->leftChild)
|
||||||
|
node->parent->leftChild = temp;
|
||||||
|
else
|
||||||
|
node->parent->rightChild = temp;
|
||||||
|
|
||||||
|
temp->leftChild = node;
|
||||||
|
node->parent = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void rotateToRight(struct pico_tree *tree, struct pico_tree_node *node)
|
||||||
|
{
|
||||||
|
struct pico_tree_node*temp;
|
||||||
|
|
||||||
|
temp = node->leftChild;
|
||||||
|
node->leftChild = temp->rightChild;
|
||||||
|
|
||||||
|
if(temp == &LEAF) return;
|
||||||
|
|
||||||
|
if(IS_NOT_LEAF(temp->rightChild))
|
||||||
|
temp->rightChild->parent = node;
|
||||||
|
|
||||||
|
temp->parent = node->parent;
|
||||||
|
|
||||||
|
if(IS_LEAF(node->parent))
|
||||||
|
tree->root = temp;
|
||||||
|
else
|
||||||
|
if(node == node->parent->rightChild)
|
||||||
|
node->parent->rightChild = temp;
|
||||||
|
else
|
||||||
|
node->parent->leftChild = temp;
|
||||||
|
|
||||||
|
temp->rightChild = node;
|
||||||
|
node->parent = temp;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct pico_tree_node *create_node(struct pico_tree *tree, void*key, uint8_t allocator)
|
||||||
|
{
|
||||||
|
struct pico_tree_node *temp = NULL;
|
||||||
|
IGNORE_PARAMETER(tree);
|
||||||
|
if(allocator == USE_PICO_ZALLOC)
|
||||||
|
temp = (struct pico_tree_node *)PICO_ZALLOC(sizeof(struct pico_tree_node));
|
||||||
|
|
||||||
|
#ifdef PICO_SUPPORT_MM
|
||||||
|
else
|
||||||
|
temp = (struct pico_tree_node *)pico_mem_page0_zalloc(sizeof(struct pico_tree_node));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(!temp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
temp->keyValue = key;
|
||||||
|
temp->parent = &LEAF;
|
||||||
|
temp->leftChild = &LEAF;
|
||||||
|
temp->rightChild = &LEAF;
|
||||||
|
/* by default every new node is red */
|
||||||
|
temp->color = RED;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function fixes the possible collisions in the tree.
|
||||||
|
* Eg. if a node is red his children must be black !
|
||||||
|
*/
|
||||||
|
static void fix_insert_collisions(struct pico_tree*tree, struct pico_tree_node*node)
|
||||||
|
{
|
||||||
|
struct pico_tree_node*temp;
|
||||||
|
|
||||||
|
while(node->parent->color == RED && IS_NOT_LEAF(GRANPA(node)))
|
||||||
|
{
|
||||||
|
if(AM_I_RIGHT_CHILD(node->parent))
|
||||||
|
{
|
||||||
|
temp = GRANPA(node)->leftChild;
|
||||||
|
if(temp->color == RED) {
|
||||||
|
node->parent->color = BLACK;
|
||||||
|
temp->color = BLACK;
|
||||||
|
GRANPA(node)->color = RED;
|
||||||
|
node = GRANPA(node);
|
||||||
|
}
|
||||||
|
else if(temp->color == BLACK) {
|
||||||
|
if(AM_I_LEFT_CHILD(node)) {
|
||||||
|
node = node->parent;
|
||||||
|
rotateToRight(tree, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
node->parent->color = BLACK;
|
||||||
|
GRANPA(node)->color = RED;
|
||||||
|
rotateToLeft(tree, GRANPA(node));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(AM_I_LEFT_CHILD(node->parent))
|
||||||
|
{
|
||||||
|
temp = GRANPA(node)->rightChild;
|
||||||
|
if(temp->color == RED) {
|
||||||
|
node->parent->color = BLACK;
|
||||||
|
temp->color = BLACK;
|
||||||
|
GRANPA(node)->color = RED;
|
||||||
|
node = GRANPA(node);
|
||||||
|
}
|
||||||
|
else if(temp->color == BLACK) {
|
||||||
|
if(AM_I_RIGHT_CHILD(node)) {
|
||||||
|
node = node->parent;
|
||||||
|
rotateToLeft(tree, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
node->parent->color = BLACK;
|
||||||
|
GRANPA(node)->color = RED;
|
||||||
|
rotateToRight(tree, GRANPA(node));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* make sure that the root of the tree stays black */
|
||||||
|
tree->root->color = BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switchNodes(struct pico_tree*tree, struct pico_tree_node*nodeA, struct pico_tree_node*nodeB)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(IS_LEAF(nodeA->parent))
|
||||||
|
tree->root = nodeB;
|
||||||
|
else
|
||||||
|
if(IS_NOT_LEAF(nodeA))
|
||||||
|
{
|
||||||
|
if(AM_I_LEFT_CHILD(nodeA))
|
||||||
|
nodeA->parent->leftChild = nodeB;
|
||||||
|
else
|
||||||
|
nodeA->parent->rightChild = nodeB;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(IS_NOT_LEAF(nodeB)) nodeB->parent = nodeA->parent;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function fixes the possible collisions in the tree.
|
||||||
|
* Eg. if a node is red his children must be black !
|
||||||
|
* In this case the function fixes the constant black path property.
|
||||||
|
*/
|
||||||
|
static void fix_delete_collisions(struct pico_tree*tree, struct pico_tree_node *node)
|
||||||
|
{
|
||||||
|
struct pico_tree_node*temp;
|
||||||
|
|
||||||
|
while( node != tree->root && node->color == BLACK && IS_NOT_LEAF(node))
|
||||||
|
{
|
||||||
|
if(AM_I_LEFT_CHILD(node)) {
|
||||||
|
|
||||||
|
temp = node->parent->rightChild;
|
||||||
|
if(temp->color == RED)
|
||||||
|
{
|
||||||
|
temp->color = BLACK;
|
||||||
|
node->parent->color = RED;
|
||||||
|
rotateToLeft(tree, node->parent);
|
||||||
|
temp = node->parent->rightChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(temp->leftChild->color == BLACK && temp->rightChild->color == BLACK)
|
||||||
|
{
|
||||||
|
temp->color = RED;
|
||||||
|
node = node->parent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(temp->rightChild->color == BLACK)
|
||||||
|
{
|
||||||
|
temp->leftChild->color = BLACK;
|
||||||
|
temp->color = RED;
|
||||||
|
rotateToRight(tree, temp);
|
||||||
|
temp = temp->parent->rightChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
temp->color = node->parent->color;
|
||||||
|
node->parent->color = BLACK;
|
||||||
|
temp->rightChild->color = BLACK;
|
||||||
|
rotateToLeft(tree, node->parent);
|
||||||
|
node = tree->root;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
temp = node->parent->leftChild;
|
||||||
|
if(temp->color == RED)
|
||||||
|
{
|
||||||
|
temp->color = BLACK;
|
||||||
|
node->parent->color = RED;
|
||||||
|
rotateToRight(tree, node->parent);
|
||||||
|
temp = node->parent->leftChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(temp->rightChild->color == BLACK && temp->leftChild->color == BLACK)
|
||||||
|
{
|
||||||
|
temp->color = RED;
|
||||||
|
node = node->parent;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(temp->leftChild->color == BLACK)
|
||||||
|
{
|
||||||
|
temp->rightChild->color = BLACK;
|
||||||
|
temp->color = RED;
|
||||||
|
rotateToLeft(tree, temp);
|
||||||
|
temp = temp->parent->leftChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
temp->color = node->parent->color;
|
||||||
|
node->parent->color = BLACK;
|
||||||
|
temp->leftChild->color = BLACK;
|
||||||
|
rotateToRight(tree, node->parent);
|
||||||
|
node = tree->root;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node->color = BLACK;
|
||||||
|
}
|
Loading…
Reference in New Issue