227 lines
5.9 KiB
C
227 lines
5.9 KiB
C
/*********************************************************************
|
|
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);
|
|
}
|
|
|