#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
#include "ip.h"
static void nfil_append_hook(Nfil *, Nfil *, Nfil *, int);
static void nfil_insert_hook(Nfil *, Nfil *, Nfil *, Nfil *, int);
static int nfil_remove_hook(Nfil *, Nfil *, int);
Nfil *nfil_in_list;
Nfil *nfil_out_list;
void
nfil_init(void)
{
print("Initializing nfil.\n");
nfil_in_list = nil;
nfil_out_list = nil;
}
int
nfil(Ipifc *ifc, Block *bp, int dir, void *xtra)
{
Nfil *nlist;
switch (dir) {
case Direction_In:
for(nlist = nfil_in_list; nlist != nil; nlist = nlist->next)
if ((nlist->exec)(ifc, bp, xtra) == Nfil_Failure)
return Nfil_Failure;
break;
case Direction_Out:
for (nlist = nfil_out_list; nlist != nil; nlist = nlist->next)
if ((nlist->exec)(ifc, bp, xtra) == Nfil_Failure)
return Nfil_Failure;
break;
default:
return Nfil_Failure;
}
return Nfil_Success;
}
int
nfil_register_hook(int (*fn)(Ipifc *, Block *, void *), int weight, int dir)
{
Nfil *nl, *li, *si = nil, *head;
if (fn == nil)
return Nfil_Failure;
/* XXX Should we panic? This could be a security issue. */
if ((nl = malloc(sizeof(Nfil))) == nil)
return Nfil_Failure;
nl->exec = fn;
nl->weight = weight;
nl->tail = nil;
if (dir == Direction_In)
head = li = nfil_in_list;
else
head = li = nfil_out_list;
/* We don't need to really do anything here except get to
* the right place in the list. Hooks with the same weight
* as one previously added will be executed in order of
* addition.
*/
for (; li != nil && li->weight <= weight;
si = li, li = li->next)
weight = weight;
/* Append function to list */
if (li == nil) {
nfil_append_hook(head, li, nl, dir);
} else {
/* We have to split the list to add the new weight */
nfil_insert_hook(head, si, li, nl, dir);
}
print("Added hook with weight %d.\n", weight);
return Nfil_Success;
}
int
nfil_unregister_hook(int (*exec)(Ipifc *, Block *, void *), int dir)
{
Nfil *head, *before = nil;
USED(before);
if (dir == Direction_In)
head = nfil_in_list;
else
head = nfil_out_list;
for (; head->exec != exec; before = head, head = head->next) ;
print("Removed hook");
return nfil_remove_hook(before, head, dir);
}
static void
nfil_append_hook(Nfil *head, Nfil *li, Nfil *nl, int dir)
{
/* It's possible that there is no list head */
if (head == nil || li == nil) {
if (dir == Direction_In)
nfil_in_list = nl;
else
nfil_out_list = nl;
} else {
/* We're appending to an existing list */
li->next = nl;
nl->next = nil;
}
/* Update tail */
if (dir == Direction_In)
nfil_in_list->tail = nl;
else
nfil_out_list->tail = nl;
}
static void
nfil_insert_hook(Nfil *head, Nfil *sf, Nfil *sa, Nfil *nl, int dir)
{
/* We're inserting before the head of the list */
if (head == sf) {
if (dir == Direction_In) {
nfil_in_list = nl;
nl->tail = head->tail;
} else {
nfil_out_list = nl;
nl->tail = head->tail;
}
nl->next = sf;
} else {
sf->next = nl;
nl->next = sa;
}
}
static int
nfil_remove_hook(Nfil *remat, Nfil *rem, int dir)
{
/* We're removing the head */
if (remat == nil) {
/* If this is the only entry in the list, just trash it */
if (rem->next == nil) {
free(rem);
/* We need the direction to reset the head to nil */
if (dir == Direction_In) nfil_in_list = nil;
else nfil_out_list = nil;
return Nfil_Success;
}
remat = malloc(sizeof(Nfil));
if (remat == nil)
return Nfil_Failure;
remat->tail = rem->tail;
}
remat->next = rem->next;
free(rem);
print("Appended hook\n");
return Nfil_Success;
}
|