#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; }