summaryrefslogtreecommitdiffstats
path: root/filter/filter.c
diff options
context:
space:
mode:
Diffstat (limited to 'filter/filter.c')
-rw-r--r--filter/filter.c212
1 files changed, 212 insertions, 0 deletions
diff --git a/filter/filter.c b/filter/filter.c
new file mode 100644
index 0000000..eb40d3c
--- /dev/null
+++ b/filter/filter.c
@@ -0,0 +1,212 @@
+/*
+ * Filters: utility functions
+ *
+ * Copyright 1998 Pavel Machek <pavel@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/signal.h>
+#include <setjmp.h>
+
+#include "nest/bird.h"
+#include "lib/lists.h"
+#include "lib/resource.h"
+#include "lib/socket.h"
+#include "nest/route.h"
+#include "nest/protocol.h"
+#include "nest/iface.h"
+#include "conf/conf.h"
+#include "filter/filter.h"
+
+struct f_inst *startup_func = NULL;
+
+#define runtime(x) do { \
+ log( L_ERR x ); \
+ res.type = T_RETURN; \
+ res.val.i = F_ERROR; \
+ return res; \
+ } while(0)
+
+#define ARG(x,y) \
+ x = interpret(what->y); \
+ if (x.type == T_RETURN) \
+ return x;
+
+#define ONEARG ARG(v1, arg1)
+#define TWOARGS ARG(v1, arg1) \
+ ARG(v2, arg2)
+#define TWOARGS_C TWOARGS \
+ if (v1.type != v2.type) \
+ runtime( "Can not operate with values of incompatible types" );
+
+static struct f_val
+interpret(struct f_inst *what)
+{
+ struct symbol *sym;
+ struct f_val v1, v2, res;
+
+ res.type = T_VOID;
+ if (!what)
+ return res;
+
+ switch(what->code) {
+ case ',':
+ TWOARGS;
+ break;
+
+/* Binary operators */
+ case '+':
+ TWOARGS_C;
+ switch (res.type = v1.type) {
+ case T_VOID: runtime( "Can not operate with values of type void" );
+ case T_INT: res.val.i = v1.val.i + v2.val.i; break;
+ default: runtime( "Usage of unknown type" );
+ }
+ break;
+ case '/':
+ TWOARGS_C;
+ switch (res.type = v1.type) {
+ case T_VOID: runtime( "Can not operate with values of type void" );
+ case T_INT: res.val.i = v1.val.i / v2.val.i; break;
+ case T_IP: if (v2.type != T_INT)
+ runtime( "Operator / is <ip>/<int>" );
+ break;
+ default: runtime( "Usage of unknown type" );
+ }
+ break;
+
+/* Relational operators */
+ case '!=':
+ case '==':
+ TWOARGS_C;
+ res.type = T_BOOL;
+ switch (v1.type) {
+ case T_VOID: runtime( "Can not operate with values of type void" );
+ case T_INT: res.val.i = (v1.val.i == v2.val.i); break;
+ default: runtime( "Usage of unknown type" );
+ }
+ if (what->code == '!=')
+ res.val.i = !(res.val.i);
+ break;
+ case '<':
+ TWOARGS_C;
+ res.type = T_BOOL;
+ switch (v1.type) {
+ case T_VOID: runtime( "Can not operate with values of type void" );
+ case T_INT: res.val.i = (v1.val.i < v2.val.i); break;
+ default: runtime( "Usage of unknown type" );
+ }
+ break;
+ case '<=':
+ TWOARGS_C;
+ res.type = T_BOOL;
+ switch (v1.type) {
+ case T_VOID: runtime( "Can not operate with values of type void" );
+ case T_INT: res.val.i = (v1.val.i <= v2.val.i); break;
+ default: runtime( "Usage of unknown type" );
+ }
+ break;
+
+/* Set */
+ case 's':
+ ARG(v2, arg2);
+ sym = what->arg1;
+ switch (res.type = v2.type) {
+ case T_VOID: runtime( "Can not assign void values" );
+ case T_INT:
+ if (sym->class != (SYM_VARIABLE | T_INT))
+ runtime( "Variable of bad type" );
+ sym->aux = v2.val.i;
+ break;
+ }
+ break;
+
+ case 'c':
+ res.type = (int) what->arg1;
+ res.val.i = (int) what->arg2;
+ break;
+ case 'i':
+ res.type = (int) what->arg1;
+ res.val.i = * ((int *) what->arg2);
+ break;
+ case 'p':
+ ONEARG;
+ switch (v1.type) {
+ case T_VOID: printf( "(void)" ); break;
+ case T_INT: printf( "%d ", v1.val.i ); break;
+ case T_STRING: printf( "%s", v1.val.i ); break;
+ default: runtime( "Print of variable of unknown type" );
+ }
+ break;
+ case '?': /* ? has really strange error value, so we can implement if ... else nicely :-) */
+ ONEARG;
+ if (v1.type != T_BOOL)
+ runtime( "If requires bool expression" );
+ if (v1.val.i) {
+ ARG(res,arg2);
+ res.val.i = 0;
+ } else res.val.i = 1;
+ res.type = T_BOOL;
+ break;
+ case '0':
+ printf( "No operation\n" );
+ break;
+ case 'p,':
+ ONEARG;
+ printf( "\n" );
+
+ switch ((int) what->arg2) {
+ case F_QUITBIRD:
+ die( "Filter asked me to die" );
+ case F_ACCEPT:
+ /* Should take care about turning ACCEPT into MODIFY */
+ case F_ERROR:
+ case F_REJECT:
+ res.type = T_RETURN;
+ res.val.i = (int) what->arg1;
+ break;
+ case F_NOP:
+ break;
+ default:
+ bug( "unknown return type: can not happen");
+ }
+ break;
+ default:
+ bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff);
+ }
+ if (what->next)
+ return interpret(what->next);
+ return res;
+}
+
+int
+f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool)
+{
+ struct f_inst *inst;
+ struct f_val res;
+ debug( "Running filter `%s'...", filter->name );
+
+ inst = filter->root;
+ res = interpret(inst);
+ if (res.type != T_RETURN)
+ return F_ERROR;
+ debug( "done (%d)\n", res.val.i );
+ return res.val.i;
+}
+
+
+void
+filters_postconfig(void)
+{
+ struct f_val res;
+ printf( "Launching startup function...\n" );
+ if (startup_func)
+ res = interpret(startup_func);
+ if (res.type = F_ERROR)
+ die( "Startup function resulted in error." );
+ printf( "done\n" );
+}