Browse code

- AVPs can be used in place of strings and integers in expressions (if (method == %method)) - Support for AVP assign statements ( %var1 = "value"; %var1 += "value2"; ) - Support for binary operators & and | in expressions - AVPs can be tested in expressions (if (%var1 == 4)) - fixed a bug in string comparisons in expressions - extended parameters of expression evaluation functions - fixed possible buffer overflow vulnerability in log("dfd") script function - default memory buffers enlarged - length of string is calculated in expression fixup - fixed bug in function printing route statements (traversed the list recursively several times)

Jan Janak authored on 30/11/2005 16:26:50
Showing 8 changed files
... ...
@@ -92,6 +92,8 @@ int do_action(struct action* a, struct sip_msg* msg)
92 92
 	struct sip_uri *u;
93 93
 	unsigned short port;
94 94
 	int proto;
95
+	unsigned short flags;
96
+	int_str name, value;
95 97
 
96 98
 	/* reset the value of error to E_UNSPEC so avoid unknowledgable
97 99
 	   functions to return with error (status<0) and not setting it
... ...
@@ -271,7 +273,7 @@ int do_action(struct action* a, struct sip_msg* msg)
271 271
 				ret=E_BUG;
272 272
 				break;
273 273
 			}
274
-			LOG(a->p1.number, a->p2.string);
274
+			LOG(a->p1.number, "%s", a->p2.string);
275 275
 			ret=1;
276 276
 			break;
277 277
 
... ...
@@ -675,6 +677,83 @@ int do_action(struct action* a, struct sip_msg* msg)
675 675
 			msg->force_send_socket=(struct socket_info*)a->p1.data;
676 676
 			ret=1; /* continue processing */
677 677
 			break;
678
+
679
+	        case ADD_T:
680
+	        case ASSIGN_T:
681
+			if (a->p2_type == STRING_ST) {
682
+				value.s = a->p2.str;
683
+				flags = a->p1.attr->type | AVP_VAL_STR;
684
+				name = a->p1.attr->name;
685
+				ret = 1;
686
+			} else if (a->p2_type == NUMBER_ST) {
687
+				value.n = a->p2.number;
688
+				flags = a->p1.attr->type;
689
+				name = a->p1.attr->name;
690
+				ret = 1;
691
+			} else if (a->p2_type == ACTION_ST) {
692
+				flags = a->p1.attr->type;
693
+				name = a->p1.attr->name;
694
+				if (&a->p2.data) {
695
+					value.n = run_actions((struct action*)a->p2.data, msg);
696
+				} else {
697
+					value.n = -1;
698
+				}
699
+				ret = value.n;
700
+			} else if(a->p2_type == EXPR_ST && a->p2.data) {
701
+				v = eval_expr((struct expr*)a->p2.data, msg);
702
+				if (v < 0) {
703
+					if (v == EXPR_DROP){ /* hack to quit on DROP*/
704
+						ret = 0;
705
+						break;
706
+					} else {
707
+						LOG(L_WARN,"WARNING: do_action: error in expression\n");
708
+					}
709
+				}
710
+				
711
+				flags = a->p1.attr->type;
712
+				name = a->p1.attr->name;
713
+				value.n = v;
714
+			} else if (a->p2_type == AVP_ST) {
715
+				struct search_state st;
716
+				avp_t* avp; 
717
+				
718
+				     /* If the action is assign then remove the old avp value before adding
719
+				      * new ones
720
+				      */
721
+				if ((unsigned char)a->type == ASSIGN_T) delete_avp(a->p1.attr->type, a->p1.attr->name);
722
+
723
+				avp = search_first_avp(a->p2.attr->type, a->p2.attr->name, &value, &st);
724
+				while(avp) {
725
+					     /* We take only the type of value and name from the source avp
726
+					      * and reset class and track flags
727
+					      */
728
+					flags = a->p1.attr->type | (avp->flags & ~(AVP_CLASS_ALL|AVP_TRACK_ALL));
729
+					if (add_avp(flags, name, value) < 0) {
730
+						LOG(L_CRIT, "ERROR: Failed to assign value to attribute\n");
731
+					 	ret=E_UNSPEC;
732
+						break;
733
+					}
734
+					avp = search_next_avp(&st, &value);
735
+				}
736
+				ret = 1;
737
+				break;
738
+			} else {
739
+				LOG(L_CRIT, "BUG: do_action: Bad right side of avp assignment\n");
740
+				ret=E_BUG;
741
+				break;
742
+			}
743
+
744
+			     /* If the action is assign then remove the old avp value before adding
745
+			      * new ones
746
+			      */
747
+			if ((unsigned char)a->type == ASSIGN_T) delete_avp(flags, name);
748
+			if (add_avp(flags, name, value) < 0) {
749
+				LOG(L_CRIT, "ERROR: Failed to assign value to attribute\n");
750
+				ret=E_UNSPEC;
751
+				break;
752
+			}
753
+			break;
754
+
678 755
 		default:
679 756
 			LOG(L_CRIT, "BUG: do_action: unknown type %d\n", a->type);
680 757
 	}
... ...
@@ -91,7 +91,6 @@
91 91
 #include "ut.h"
92 92
 #include "dset.h"
93 93
 
94
-
95 94
 #include "config.h"
96 95
 #ifdef USE_TLS
97 96
 #include "tls/tls_config.h"
... ...
@@ -116,10 +115,10 @@ static int rt;  /* Type of route block for find_export */
116 116
 static str* str_tmp;
117 117
 static str s_tmp;
118 118
 static struct ip_addr* ip_tmp;
119
+static struct avp_spec* s_attr;
119 120
 
120 121
 static void warn(char* s);
121 122
 static struct socket_id* mk_listen_id(char*, int, int);
122
- 
123 123
 
124 124
 %}
125 125
 
... ...
@@ -132,6 +131,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
132 132
 	struct net* ipnet;
133 133
 	struct ip_addr* ipaddr;
134 134
 	struct socket_id* sockid;
135
+	struct avp_spec* attr;
135 136
 }
136 137
 
137 138
 /* terminals */
... ...
@@ -263,8 +263,13 @@ static struct socket_id* mk_listen_id(char*, int, int);
263 263
 %token MCAST_TTL
264 264
 %token TOS
265 265
 
266
-
267
-
266
+%token ATTR_MARK
267
+%token ATTR_FROM
268
+%token ATTR_TO
269
+%token ATTR_USER
270
+%token ATTR_DOMAIN
271
+%token ATTR_GLOBAL
272
+%token ADD
268 273
 
269 274
 /* operators */
270 275
 %nonassoc EQUAL
... ...
@@ -275,11 +280,12 @@ static struct socket_id* mk_listen_id(char*, int, int);
275 275
 %nonassoc LTE
276 276
 %nonassoc DIFF
277 277
 %nonassoc MATCH
278
-%left OR
279
-%left AND
280
-%left NOT
281
-%left PLUS
282
-%left MINUS
278
+%left LOG_OR
279
+%left LOG_AND
280
+%left BIN_OR
281
+%left BIN_AND 
282
+%left PLUS MINUS
283
+%right NOT
283 284
 
284 285
 /* values */
285 286
 %token <intval> NUMBER
... ...
@@ -305,7 +311,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
305 305
 
306 306
 /*non-terminals */
307 307
 %type <expr> exp exp_elem /*, condition*/
308
-%type <action> action actions cmd if_cmd stm exp_stm
308
+%type <action> action actions cmd if_cmd stm exp_stm assign_action
309 309
 %type <ipaddr> ipv4 ipv6 ipv6addr ip
310 310
 %type <ipnet> ipnet
311 311
 %type <strval> host
... ...
@@ -313,9 +319,12 @@ static struct socket_id* mk_listen_id(char*, int, int);
313 313
 %type <sockid>  id_lst
314 314
 %type <sockid>  phostport
315 315
 %type <intval> proto port
316
-%type <intval> equalop strop intop
316
+%type <intval> equalop strop intop binop
317 317
 %type <strval> host_sep
318 318
 %type <intval> uri_type
319
+%type <attr> attr_id
320
+%type <intval> class_id
321
+%type <intval> assign_op
319 322
 /*%type <route_el> rules;
320 323
   %type <route_el> rule;
321 324
 */
... ...
@@ -908,8 +917,8 @@ rule:	condition	actions CR {
908 908
 condition:	exp {$$=$1;}
909 909
 */
910 910
 
911
-exp:	exp AND exp 	{ $$=mk_exp(AND_OP, $1, $3); }
912
-	| exp OR  exp		{ $$=mk_exp(OR_OP, $1, $3);  }
911
+exp:	exp LOG_AND exp 	{ $$=mk_exp(LOGAND_OP, $1, $3); }
912
+	| exp LOG_OR  exp		{ $$=mk_exp(LOGOR_OP, $1, $3);  }
913 913
 	| NOT exp 			{ $$=mk_exp(NOT_OP, $2, 0);  }
914 914
 	| LPAREN exp RPAREN	{ $$=$2; }
915 915
 	| exp_elem			{ $$=$1; }
... ...
@@ -925,6 +934,10 @@ intop:	equalop	{$$=$1; }
925 925
 		| GTE	{$$=GTE_OP; }
926 926
 		| LTE	{$$=LTE_OP; }
927 927
 		;
928
+
929
+binop : BIN_OR { $$= BINOR_OP; }
930
+      | BIN_AND { $$ = BINAND_OP; }
931
+;
928 932
 		
929 933
 strop:	equalop	{$$=$1; }
930 934
 		| MATCH	{$$=MATCH_OP; }
... ...
@@ -935,82 +948,74 @@ uri_type:	URI			{$$=URI_O;}
935 935
 		|	TO_URI		{$$=TO_URI_O;}
936 936
 		;
937 937
 
938
-exp_elem:	METHOD strop STRING	{$$= mk_elem(	$2, STRING_ST, 
939
-													METHOD_O, $3);
940
-									}
941
-		| METHOD strop  ID	{$$ = mk_elem(	$2, STRING_ST,
942
-											METHOD_O, $3); 
943
-				 			}
938
+exp_elem:	METHOD strop STRING	{$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
939
+                | METHOD strop attr_id  {$$ = mk_elem($2, METHOD_O, 0, AVP_ST, $3); }
940
+		| METHOD strop  ID	{$$ = mk_elem($2, METHOD_O, 0, STRING_ST,$3); }
944 941
 		| METHOD strop error { $$=0; yyerror("string expected"); }
945 942
 		| METHOD error	{ $$=0; yyerror("invalid operator,"
946 943
 										"== , !=, or =~ expected");
947 944
 						}
948
-		| uri_type strop STRING	{$$ = mk_elem(	$2, STRING_ST,
949
-												$1, $3); 
950
-				 				}
951
-		| uri_type strop host 	{$$ = mk_elem(	$2, STRING_ST,
952
-											$1, $3); 
953
-				 			}
954
-		| uri_type equalop MYSELF	{ $$=mk_elem(	$2, MYSELF_ST,
955
-													$1, 0);
956
-								}
945
+		| uri_type strop STRING	{$$ = mk_elem($2, $1, 0, STRING_ST, $3); }
946
+                | uri_type strop host 	{$$ = mk_elem($2, $1, 0, STRING_ST, $3); }
947
+                | uri_type strop attr_id {$$ = mk_elem($2, $1, 0, AVP_ST, $3); }
948
+                | uri_type equalop MYSELF {$$=mk_elem($2, $1, 0, MYSELF_ST, 0); }
957 949
 		| uri_type strop error { $$=0; yyerror("string or MYSELF expected"); }
958 950
 		| uri_type error	{ $$=0; yyerror("invalid operator,"
959 951
 									" == , != or =~ expected");
960 952
 					}
961
-		| SRCPORT intop NUMBER	{ $$=mk_elem(	$2, NUMBER_ST,
962
-												SRCPORT_O, (void *) $3 ); }
953
+		| SRCPORT intop NUMBER	{ $$=mk_elem($2, SRCPORT_O, 0, NUMBER_ST, (void*)$3 ); }
954
+                | SRCPORT intop attr_id { $$=mk_elem($2, SRCPORT_O, 0, AVP_ST, (void*)$3 ); }
963 955
 		| SRCPORT intop error { $$=0; yyerror("number expected"); }
964 956
 		| SRCPORT error { $$=0; yyerror("==, !=, <,>, >= or <=  expected"); }
965
-		| DSTPORT intop NUMBER	{ $$=mk_elem(	$2, NUMBER_ST,
966
-												DSTPORT_O, (void *) $3 ); }
957
+
958
+		| DSTPORT intop NUMBER	{ $$=mk_elem($2, DSTPORT_O, 0, NUMBER_ST, (void*)$3 ); }
959
+		| DSTPORT intop attr_id	{ $$=mk_elem($2, DSTPORT_O, 0, AVP_ST, (void*)$3 ); }
967 960
 		| DSTPORT intop error { $$=0; yyerror("number expected"); }
968 961
 		| DSTPORT error { $$=0; yyerror("==, !=, <,>, >= or <=  expected"); }
969
-		| PROTO intop proto	{ $$=mk_elem(	$2, NUMBER_ST,
970
-												PROTO_O, (void *) $3 ); }
962
+
963
+		| PROTO intop proto	{ $$=mk_elem($2, PROTO_O, 0, NUMBER_ST, (void*)$3 ); }
964
+		| PROTO intop attr_id	{ $$=mk_elem($2, PROTO_O, 0, AVP_ST, (void*)$3 ); }
971 965
 		| PROTO intop error { $$=0;
972 966
 								yyerror("protocol expected (udp, tcp or tls)");
973 967
 							}
974 968
 		| PROTO error { $$=0; yyerror("equal/!= operator expected"); }
975
-		| AF intop NUMBER	{ $$=mk_elem(	$2, NUMBER_ST,
976
-												AF_O, (void *) $3 ); }
969
+
970
+		| AF intop NUMBER	{ $$=mk_elem($2, AF_O, 0, NUMBER_ST,(void *) $3 ); }
971
+		| AF intop attr_id	{ $$=mk_elem($2, AF_O, 0, AVP_ST,(void *) $3 ); }
977 972
 		| AF intop error { $$=0; yyerror("number expected"); }
978 973
 		| AF error { $$=0; yyerror("equal/!= operator expected"); }
979
-		| MSGLEN intop NUMBER	{ $$=mk_elem(	$2, NUMBER_ST,
980
-												MSGLEN_O, (void *) $3 ); }
981
-		| MSGLEN intop MAX_LEN	{ $$=mk_elem(	$2, NUMBER_ST,
982
-												MSGLEN_O, (void *) BUF_SIZE); }
974
+
975
+		| MSGLEN intop NUMBER	{ $$=mk_elem($2, MSGLEN_O, 0, NUMBER_ST, (void *) $3 ); }
976
+		| MSGLEN intop attr_id	{ $$=mk_elem($2, MSGLEN_O, 0, AVP_ST, (void *) $3 ); }
977
+		| MSGLEN intop MAX_LEN	{ $$=mk_elem($2, MSGLEN_O, 0, NUMBER_ST, (void *) BUF_SIZE); }
983 978
 		| MSGLEN intop error { $$=0; yyerror("number expected"); }
984 979
 		| MSGLEN error { $$=0; yyerror("equal/!= operator expected"); }
985
-		| SRCIP equalop ipnet	{ $$=mk_elem(	$2, NET_ST,
986
-												SRCIP_O, $3);
987
-								}
980
+
981
+		| SRCIP equalop ipnet	{ $$=mk_elem($2, SRCIP_O, 0, NET_ST, $3); }
988 982
 		| SRCIP strop STRING	{	s_tmp.s=$3;
989 983
 									s_tmp.len=strlen($3);
990 984
 									ip_tmp=str2ip(&s_tmp);
991 985
 									if (ip_tmp==0)
992 986
 										ip_tmp=str2ip6(&s_tmp);
993 987
 									if (ip_tmp){
994
-										$$=mk_elem(	$2, NET_ST, SRCIP_O,
988
+										$$=mk_elem(	$2, SRCIP_O, 0, NET_ST,
995 989
 												mk_net_bitlen(ip_tmp, 
996 990
 														ip_tmp->len*8) );
997 991
 									}else{
998
-										$$=mk_elem(	$2, STRING_ST,
999
-												SRCIP_O, $3);
992
+										$$=mk_elem(	$2, SRCIP_O, 0, STRING_ST,
993
+												$3);
1000 994
 									}
1001 995
 								}
1002
-		| SRCIP strop host	{ $$=mk_elem(	$2, STRING_ST,
1003
-												SRCIP_O, $3);
1004
-								}
1005
-		| SRCIP equalop MYSELF  { $$=mk_elem(	$2, MYSELF_ST,
1006
-												SRCIP_O, 0);
996
+		| SRCIP strop host	{ $$=mk_elem(	$2, SRCIP_O, 0, STRING_ST, $3); }
997
+		| SRCIP equalop MYSELF  { $$=mk_elem(	$2, SRCIP_O, 0, MYSELF_ST,
998
+												0);
1007 999
 								}
1008 1000
 		| SRCIP strop error { $$=0; yyerror( "ip address or hostname"
1009 1001
 						 "expected" ); }
1010 1002
 		| SRCIP error  { $$=0; 
1011 1003
 						 yyerror("invalid operator, ==, != or =~ expected");}
1012
-		| DSTIP equalop ipnet	{ $$=mk_elem(	$2, NET_ST,
1013
-												DSTIP_O, $3);
1004
+		| DSTIP equalop ipnet	{ $$=mk_elem(	$2, DSTIP_O, 0, NET_ST,
1005
+												(void*)$3);
1014 1006
 								}
1015 1007
 		| DSTIP strop STRING	{	s_tmp.s=$3;
1016 1008
 									s_tmp.len=strlen($3);
... ...
@@ -1018,41 +1023,49 @@ exp_elem:	METHOD strop STRING	{$$= mk_elem(	$2, STRING_ST,
1018 1018
 									if (ip_tmp==0)
1019 1019
 										ip_tmp=str2ip6(&s_tmp);
1020 1020
 									if (ip_tmp){
1021
-										$$=mk_elem(	$2, NET_ST, DSTIP_O,
1021
+										$$=mk_elem(	$2, DSTIP_O, 0, NET_ST,
1022 1022
 												mk_net_bitlen(ip_tmp, 
1023 1023
 														ip_tmp->len*8) );
1024 1024
 									}else{
1025
-										$$=mk_elem(	$2, STRING_ST,
1026
-												DSTIP_O, $3);
1025
+										$$=mk_elem(	$2, DSTIP_O, 0, STRING_ST,
1026
+												$3);
1027 1027
 									}
1028 1028
 								}
1029
-		| DSTIP strop host	{ $$=mk_elem(	$2, STRING_ST,
1030
-												DSTIP_O, $3);
1029
+		| DSTIP strop host	{ $$=mk_elem(	$2, DSTIP_O, 0, STRING_ST,
1030
+												$3);
1031 1031
 								}
1032
-		| DSTIP equalop MYSELF  { $$=mk_elem(	$2, MYSELF_ST,
1033
-												DSTIP_O, 0);
1032
+		| DSTIP equalop MYSELF  { $$=mk_elem(	$2, DSTIP_O, 0, MYSELF_ST,
1033
+												0);
1034 1034
 								}
1035 1035
 		| DSTIP strop error { $$=0; yyerror( "ip address or hostname"
1036 1036
 						 			"expected" ); }
1037 1037
 		| DSTIP error { $$=0; 
1038 1038
 						yyerror("invalid operator, ==, != or =~ expected");}
1039
-		| MYSELF equalop uri_type	{ $$=mk_elem(	$2, MYSELF_ST,
1040
-													$3, 0);
1039
+
1040
+		| MYSELF equalop uri_type	{ $$=mk_elem(	$2, $3, 0, MYSELF_ST,
1041
+												       0);
1041 1042
 								}
1042
-		| MYSELF equalop SRCIP  { $$=mk_elem(	$2, MYSELF_ST,
1043
-												SRCIP_O, 0);
1043
+		| MYSELF equalop SRCIP  { $$=mk_elem(	$2, SRCIP_O, 0, MYSELF_ST,
1044
+												0);
1044 1045
 								}
1045
-		| MYSELF equalop DSTIP  { $$=mk_elem(	$2, MYSELF_ST,
1046
-												DSTIP_O, 0);
1046
+                | MYSELF equalop DSTIP  { $$=mk_elem(	$2, DSTIP_O, 0, MYSELF_ST,
1047
+							0);
1047 1048
 								}
1048 1049
 		| MYSELF equalop error {	$$=0; 
1049 1050
 									yyerror(" URI, SRCIP or DSTIP expected"); }
1050 1051
 		| MYSELF error	{ $$=0; 
1051 1052
 							yyerror ("invalid operator, == or != expected");
1052 1053
 						}
1053
-		| exp_stm			{ $$=mk_elem( NO_OP, ACTIONS_ST, ACTION_O, $1 );  }
1054
-		| NUMBER		{$$=mk_elem( NO_OP, NUMBER_ST, NUMBER_O, (void*)$1 ); }
1055
-	;
1054
+		| exp_stm			{ $$=mk_elem( NO_OP, ACTION_O, 0, ACTIONS_ST, $1);  }
1055
+		| NUMBER		{$$=mk_elem( NO_OP, NUMBER_O, 0, NUMBER_ST, (void*)$1 ); }
1056
+
1057
+		| attr_id		{$$=mk_elem( NO_OP, AVP_ST, (void*)$1, 0, 0); }
1058
+		| attr_id strop STRING	{$$=mk_elem( $2, AVP_ST, (void*)$1, STRING_ST, $3); }
1059
+		| attr_id intop NUMBER	{$$=mk_elem( $2, AVP_ST, (void*)$1, NUMBER_ST, (void*)$3); }
1060
+		| attr_id binop NUMBER	{$$=mk_elem( $2, AVP_ST, (void*)$1, NUMBER_ST, (void*)$3); }
1061
+                | attr_id strop attr_id {$$=mk_elem( $2, AVP_ST, (void*)$1, AVP_ST, (void*)$3); }
1062
+;
1063
+
1056 1064
 
1057 1065
 ipnet:	ip SLASH ip	{ $$=mk_net($1, $3); } 
1058 1066
 	| ip SLASH NUMBER 	{	if (($3<0) || ($3>$1->len*8)){
... ...
@@ -1097,6 +1110,7 @@ host:	ID				{ $$=$1; }
1097 1097
 
1098 1098
 exp_stm:	cmd						{ $$=$1; }
1099 1099
 		|	if_cmd					{ $$=$1; }
1100
+                |       assign_action { $$ = $1; }
1100 1101
 		|	LBRACE actions RBRACE	{ $$=$2; }
1101 1102
 	;
1102 1103
 
... ...
@@ -1111,6 +1125,7 @@ actions:	actions action	{$$=append_action($1, $2); }
1111 1111
 
1112 1112
 action:		cmd SEMICOLON {$$=$1;}
1113 1113
 		| if_cmd {$$=$1;}
1114
+                | assign_action SEMICOLON {$$=$1}
1114 1115
 		| SEMICOLON /* null action */ {$$=0;}
1115 1116
 		| cmd error { $$=0; yyerror("bad command: missing ';'?"); }
1116 1117
 	;
... ...
@@ -1133,6 +1148,61 @@ if_cmd:		IF exp stm				{ $$=mk_action3( IF_T,
1133 1133
 									}
1134 1134
 	;
1135 1135
 
1136
+class_id : LBRACK ATTR_USER RBRACK { $$ = AVP_CLASS_USER; }
1137
+         | LBRACK ATTR_DOMAIN RBRACK { $$ = AVP_CLASS_DOMAIN; }
1138
+         | LBRACK ATTR_GLOBAL RBRACK { $$ = AVP_CLASS_GLOBAL; }
1139
+;
1140
+
1141
+attr_id : ATTR_MARK ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
1142
+                         if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
1143
+                         s_attr->type = AVP_NAME_STR;                   
1144
+                         s_attr->name.s.s = $2; s_attr->name.s.len = strlen($2); 
1145
+                         $$ = s_attr; 
1146
+                       }
1147
+        | ATTR_MARK class_id DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
1148
+                                      if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
1149
+                                      s_attr->type = AVP_NAME_STR | $2;
1150
+                                      s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4); 
1151
+                                      $$ = s_attr; 
1152
+                                    }
1153
+        | ATTR_MARK ATTR_FROM DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
1154
+                                       if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
1155
+                                       s_attr->type = AVP_NAME_STR | AVP_TRACK_FROM;
1156
+                                       s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4);
1157
+                                       $$ = s_attr;
1158
+                                     }
1159
+        | ATTR_MARK ATTR_TO DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
1160
+                                     if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
1161
+                                     s_attr->type = AVP_NAME_STR | AVP_TRACK_TO; 
1162
+                                     s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4); 
1163
+                                     $$ = s_attr;
1164
+                                   }
1165
+        | ATTR_MARK ATTR_FROM class_id DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
1166
+                                               if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
1167
+                                               s_attr->type = AVP_NAME_STR | AVP_TRACK_FROM | $3; 
1168
+                                               s_attr->name.s.s = $5; 
1169
+                                               s_attr->name.s.len = strlen($5);
1170
+                                               $$ = s_attr;
1171
+                                              }
1172
+        | ATTR_MARK ATTR_TO class_id DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
1173
+                                              if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
1174
+                                              s_attr->type = AVP_NAME_STR | AVP_TRACK_TO | $3;
1175
+                                              s_attr->name.s.s = $5; s_attr->name.s.len = strlen($5);
1176
+                                             $$ = s_attr;
1177
+                                            }
1178
+;
1179
+
1180
+assign_op : ADD { $$ = ADD_T; }
1181
+          | EQUAL { $$ = ASSIGN_T; }
1182
+;
1183
+
1184
+assign_action:   attr_id assign_op STRING  { $$=mk_action($2, AVP_ST, STRING_ST, $1, $3); }
1185
+               | attr_id assign_op NUMBER  { $$=mk_action($2, AVP_ST, NUMBER_ST, $1, (void*)$3); }
1186
+               | attr_id assign_op cmd     { $$=mk_action($2, AVP_ST, ACTION_ST, $1, $3); }
1187
+               | attr_id assign_op attr_id { $$=mk_action($2, AVP_ST, AVP_ST, $1, $3); }
1188
+               | attr_id assign_op LPAREN exp RPAREN { $$ = mk_action($2, AVP_ST, EXPR_ST, $1, $4); }
1189
+;
1190
+
1136 1191
 cmd:		FORWARD LPAREN host RPAREN	{ $$=mk_action(	FORWARD_T,
1137 1192
 														STRING_ST,
1138 1193
 														NUMBER_ST,
... ...
@@ -119,10 +119,10 @@
119 119
 #define SRV_MAX_PREFIX_LEN SRV_TLS_PREFIX_LEN
120 120
 
121 121
 /*used only if PKG_MALLOC is defined*/
122
-#define PKG_MEM_POOL_SIZE 1024*1024
122
+#define PKG_MEM_POOL_SIZE 4*1024*1024
123 123
 
124 124
 /*used if SH_MEM is defined*/
125
-#define SHM_MEM_SIZE 32
125
+#define SHM_MEM_SIZE 128
126 126
 
127 127
 #define TIMER_TICK 1
128 128
 
... ...
@@ -142,25 +142,25 @@ int str2facility(char *s);
142 142
 					else { \
143 143
 						switch(lev){ \
144 144
 							case L_CRIT: \
145
-								syslog(LOG_CRIT|log_facility, fmt, ##args); \
145
+								syslog(LOG_CRIT|log_facility, "CRIT: " fmt, ##args); \
146 146
 								break; \
147 147
 							case L_ALERT: \
148
-								syslog(LOG_ALERT|log_facility, fmt, ##args); \
148
+								syslog(LOG_ALERT|log_facility, "ALERT: " fmt, ##args); \
149 149
 								break; \
150 150
 							case L_ERR: \
151
-								syslog(LOG_ERR|log_facility, fmt, ##args); \
151
+								syslog(LOG_ERR|log_facility, "ERROR: " fmt, ##args); \
152 152
 								break; \
153 153
 							case L_WARN: \
154
-								syslog(LOG_WARNING|log_facility, fmt, ##args);\
154
+								syslog(LOG_WARNING|log_facility, "WARNING: " fmt, ##args);\
155 155
 								break; \
156 156
 							case L_NOTICE: \
157
-								syslog(LOG_NOTICE|log_facility, fmt, ##args); \
157
+								syslog(LOG_NOTICE|log_facility, "NOTICE: " fmt, ##args); \
158 158
 								break; \
159 159
 							case L_INFO: \
160
-								syslog(LOG_INFO|log_facility, fmt, ##args); \
160
+								syslog(LOG_INFO|log_facility, "INFO: " fmt, ##args); \
161 161
 								break; \
162 162
 							case L_DBG: \
163
-								syslog(LOG_DEBUG|log_facility, fmt, ##args); \
163
+								syslog(LOG_DEBUG|log_facility, "DEBUG: " fmt, ##args); \
164 164
 								break; \
165 165
 						} \
166 166
 					} \
... ...
@@ -126,7 +126,7 @@
126 126
 #include "tls/tls_init.h"
127 127
 #endif
128 128
 #endif
129
-
129
+#include "usr_avp.h"
130 130
 
131 131
 
132 132
 #include "stats.h"
... ...
@@ -1568,6 +1568,8 @@ try_again:
1568 1568
 		goto error;
1569 1569
 	}
1570 1570
 	
1571
+	if (init_avps()<0) goto error;
1572
+
1571 1573
 #ifdef USE_TCP
1572 1574
 	if (!tcp_disable){
1573 1575
 		/*init tcp*/
... ...
@@ -92,8 +92,8 @@ static int fix_expr(struct expr* exp)
92 92
 	}
93 93
 	if (exp->type==EXP_T){
94 94
 		switch(exp->op){
95
-			case AND_OP:
96
-			case OR_OP:
95
+			case LOGAND_OP:
96
+			case LOGOR_OP:
97 97
 						if ((ret=fix_expr(exp->l.expr))!=0)
98 98
 							return ret;
99 99
 						ret=fix_expr(exp->r.expr);
... ...
@@ -107,7 +107,11 @@ static int fix_expr(struct expr* exp)
107 107
 		}
108 108
 	}else if (exp->type==ELEM_T){
109 109
 			if (exp->op==MATCH_OP){
110
-				if (exp->subtype==STRING_ST){
110
+				     /* right side either has to be string, in which case
111
+				      * we turn it into regular expression, or it is regular
112
+				      * expression already. In that case we do nothing
113
+				      */
114
+				if (exp->r_type==STRING_ST){
111 115
 					re=(regex_t*)pkg_malloc(sizeof(regex_t));
112 116
 					if (re==0){
113 117
 						LOG(L_CRIT, "ERROR: fix_expr: memory allocation"
... ...
@@ -123,20 +127,35 @@ static int fix_expr(struct expr* exp)
123 123
 					}
124 124
 					/* replace the string with the re */
125 125
 					pkg_free(exp->r.param);
126
-					exp->r.param=re;
127
-					exp->subtype=RE_ST;
128
-				}else if (exp->subtype!=RE_ST){
126
+					exp->r.re=re;
127
+					exp->r_type=RE_ST;
128
+				}else if (exp->r_type!=RE_ST && exp->r_type != AVP_ST){
129 129
 					LOG(L_CRIT, "BUG: fix_expr : invalid type for match\n");
130 130
 					return E_BUG;
131 131
 				}
132 132
 			}
133
-			if (exp->l.operand==ACTION_O){
133
+			if (exp->l_type==ACTION_O){
134 134
 				ret=fix_actions((struct action*)exp->r.param);
135 135
 				if (ret!=0){
136 136
 					LOG(L_CRIT, "ERROR: fix_expr : fix_actions error\n");
137 137
 					return ret;
138 138
 				}
139 139
 			}
140
+			     /* Calculate lengths of strings */
141
+			if (exp->l_type==STRING_ST) {
142
+				int len;
143
+				if (exp->l.string) len = strlen(exp->l.string);
144
+				else len = 0;
145
+				exp->l.str.s = exp->l.string;
146
+				exp->l.str.len = len;
147
+			}
148
+			if (exp->r_type==STRING_ST) {
149
+				int len;
150
+				if (exp->l.string) len = strlen(exp->r.string);
151
+				else len = 0;
152
+				exp->r.str.s = exp->r.string;
153
+				exp->r.str.len = len;
154
+			}
140 155
 			ret=0;
141 156
 	}
142 157
 	return ret;
... ...
@@ -230,6 +249,37 @@ static int fix_actions(struct action* a)
230 230
 						return ret;
231 231
 				}
232 232
 				break;
233
+
234
+		        case ASSIGN_T:
235
+		        case ADD_T:
236
+				if (t->p1_type != AVP_ST) {
237
+					LOG(L_CRIT, "BUG: fix_actions: Invalid left side of assignment\n");
238
+					return E_BUG;
239
+				}
240
+				if (t->p1.attr->type & AVP_CLASS_DOMAIN) {
241
+					LOG(L_ERR, "ERROR: You cannot change domain attributes from the script, they are read-only\n");
242
+					return E_BUG;
243
+				} else if (t->p1.attr->type & AVP_CLASS_GLOBAL) {
244
+					LOG(L_ERR, "ERROR: You cannot change global attributes from the script, they are read-only\n");
245
+					return E_BUG;
246
+				}
247
+
248
+				if (t->p2_type == ACTION_ST && t->p2.data) {
249
+					if ((ret = fix_actions((struct action*)t->p2.data)) < 0) {
250
+						return ret;
251
+					}
252
+				} else if (t->p2_type == EXPR_ST && t->p2.data) {
253
+					if ((ret = fix_expr((struct expr*)t->p2.data)) < 0) {
254
+						return ret;
255
+					}
256
+				} else if (t->p2_type == STRING_ST) {
257
+					int len;
258
+					len = strlen(t->p2.data);
259
+					t->p2.str.s = t->p2.data;
260
+					t->p2.str.len = len;
261
+				}
262
+				break;
263
+
233 264
 			case MODULE_T:
234 265
 				if ((mod=find_module(t->p1.data, &cmd))!=0){
235 266
 					DBG("fixing %s %s\n", mod->path, cmd->name);
... ...
@@ -280,78 +330,113 @@ static int fix_actions(struct action* a)
280 280
 }
281 281
 
282 282
 
283
-inline static int comp_no( int port, void *param, int op, int subtype )
283
+/* Compare parameters as ordinary numbers
284
+ *
285
+ * Left and right operands can be either numbers or
286
+ * attributes. If either of the attributes if of string type then the length of
287
+ * its value will be used.
288
+ */
289
+inline static int comp_num(int op, long left, int rtype, union exp_op* r)
284 290
 {
291
+	int_str val;
292
+	avp_t* avp;
293
+	long right;
285 294
 	
286
-	if (subtype!=NUMBER_ST) {
287
-		LOG(L_CRIT, "BUG: comp_no: number expected: %d\n", subtype );
295
+	if (rtype == AVP_ST) {
296
+		avp = search_first_avp(r->attr->type, r->attr->name, &val, 0);
297
+		if (avp && !(avp->flags & AVP_VAL_STR)) right = val.n;
298
+		else return 0; /* Always fail */
299
+	} else if (rtype == NUMBER_ST) {
300
+		right = r->intval;
301
+	} else {
302
+		LOG(L_CRIT, "BUG: comp_num: Invalid right operand (%d)\n", rtype);
288 303
 		return E_BUG;
289 304
 	}
305
+
290 306
 	switch (op){
291
-		case EQUAL_OP:
292
-			return port==(long)param;
293
-		case DIFF_OP:
294
-			return port!=(long)param;
295
-		case GT_OP:
296
-			return port>(long)param;
297
-		case LT_OP:
298
-			return port<(long)param;
299
-		case GTE_OP:
300
-			return port>=(long)param;
301
-		case LTE_OP:
302
-			return port<=(long)param;
303
-		default:
304
-		LOG(L_CRIT, "BUG: comp_no: unknown operator: %d\n", op );
307
+	case EQUAL_OP: return (long)left == (long)right;
308
+	case DIFF_OP:  return (long)left != (long)right;
309
+	case GT_OP:    return (long)left >  (long)right;
310
+	case LT_OP:    return (long)left <  (long)right;
311
+	case GTE_OP:   return (long)left >= (long)right;
312
+	case LTE_OP:   return (long)left <= (long)right;
313
+	default:
314
+		LOG(L_CRIT, "BUG: comp_num: unknown operator: %d\n", op);
305 315
 		return E_BUG;
306 316
 	}
307 317
 }
308 318
 
309
-/* eval_elem helping function, returns str op param */
310
-inline static int comp_strstr(str* str, void* param, int op, int subtype)
319
+/*
320
+ * Compare given string "left" with right side of expression
321
+ */
322
+inline static int comp_str(int op, str* left, int rtype, union exp_op* r)
311 323
 {
324
+	str* right;
325
+	int_str val;
326
+	avp_t* avp;
312 327
 	int ret;
313 328
 	char backup;
314 329
 	
330
+	if (rtype == AVP_ST) {
331
+		avp = search_first_avp(r->attr->type, r->attr->name, &val, 0);
332
+		if (avp && (avp->flags & AVP_VAL_STR)) right = &val.s;
333
+		else return 0;
334
+	} else if ((op == MATCH_OP && rtype == RE_ST)) {
335
+	} else if (op != MATCH_OP && rtype == STRING_ST) {
336
+		right = &r->str;
337
+	} else {
338
+		LOG(L_CRIT, "BUG: comp_str: Bad type %d, "
339
+		    "string or RE expected\n", rtype);
340
+		goto error;
341
+	}
342
+
315 343
 	ret=-1;
316 344
 	switch(op){
317 345
 		case EQUAL_OP:
318
-			if (subtype!=STRING_ST){
319
-				LOG(L_CRIT, "BUG: comp_str: bad type %d, "
320
-						"string expected\n", subtype);
321
-				goto error;
322
-			}
323
-			ret=(strncasecmp(str->s, (char*)param, str->len)==0);
346
+			if (left->len != right->len) return 0;
347
+			ret=(strncasecmp(left->s, right->s, left->len)==0);
324 348
 			break;
325 349
 		case DIFF_OP:
326
-			if (subtype!=STRING_ST){
327
-				LOG(L_CRIT, "BUG: comp_str: bad type %d, "
328
-						"string expected\n", subtype);
329
-				goto error;
330
-			}
331
-			ret=(strncasecmp(str->s, (char*)param, str->len)!=0);
350
+			if (left->len != right->len) return 1;
351
+			ret = (strncasecmp(left->s, right->s, left->len)!=0);
332 352
 			break;
333 353
 		case MATCH_OP:
334
-			if (subtype!=RE_ST){
335
-				LOG(L_CRIT, "BUG: comp_str: bad type %d, "
336
-						" RE expected\n", subtype);
337
-				goto error;
354
+			     /* this is really ugly -- we put a temporary zero-terminating
355
+			      * character in the original string; that's because regexps
356
+			      * take 0-terminated strings and our messages are not
357
+			      * zero-terminated; it should not hurt as long as this function
358
+			      * is applied to content of pkg mem, which is always the case
359
+			      * with calls from route{}; the same goes for fline in reply_route{};
360
+			      *
361
+			      * also, the received function should always give us an extra
362
+			      * character, into which we can put the 0-terminator now;
363
+			      * an alternative would be allocating a new piece of memory,
364
+			      * which might be too slow
365
+			      * -jiri
366
+			      *
367
+			      * janakj: AVPs are zero terminated too so this is not problem either
368
+			      */
369
+			backup=left->s[left->len];
370
+			left->s[left->len]='\0';
371
+			if (rtype == AVP_ST) {
372
+				regex_t* re;
373
+				     /* For AVPs we need to compile the RE on the fly */
374
+				re=(regex_t*)pkg_malloc(sizeof(regex_t));
375
+				if (re==0){
376
+					LOG(L_CRIT, "ERROR: comp_strstr: memory allocation"
377
+					    " failure\n");
378
+					goto error;
379
+				}
380
+				if (regcomp(re, right->s, REG_EXTENDED|REG_NOSUB|REG_ICASE)) {
381
+					pkg_free(re);
382
+					goto error;
383
+				}				
384
+				ret=(regexec(re, left->s, 0, 0, 0)==0);
385
+				pkg_free(re);
386
+			} else {
387
+				ret=(regexec(r->re, left->s, 0, 0, 0)==0);
338 388
 			}
339
-		/* this is really ugly -- we put a temporary zero-terminating
340
-		 * character in the original string; that's because regexps
341
-         * take 0-terminated strings and our messages are not
342
-         * zero-terminated; it should not hurt as long as this function
343
-		 * is applied to content of pkg mem, which is always the case
344
-		 * with calls from route{}; the same goes for fline in reply_route{};
345
-         *
346
-         * also, the received function should always give us an extra
347
-         * character, into which we can put the 0-terminator now;
348
-         * an alternative would be allocating a new piece of memory,
349
-         * which might be too slow
350
-         * -jiri
351
-         */
352
-			backup=str->s[str->len];str->s[str->len]=0;
353
-			ret=(regexec((regex_t*)param, str->s, 0, 0, 0)==0);
354
-			str->s[str->len]=backup;
389
+			left->s[left->len] = backup;
355 390
 			break;
356 391
 		default:
357 392
 			LOG(L_CRIT, "BUG: comp_str: unknown op %d\n", op);
... ...
@@ -363,39 +448,40 @@ error:
363 363
 	return -1;
364 364
 }
365 365
 
366
+
366 367
 /* eval_elem helping function, returns str op param */
367
-inline static int comp_str(char* str, void* param, int op, int subtype)
368
+inline static int comp_string(int op, char* left, int rtype, union exp_op* r)
368 369
 {
369 370
 	int ret;
370 371
 	
371 372
 	ret=-1;
372 373
 	switch(op){
373 374
 		case EQUAL_OP:
374
-			if (subtype!=STRING_ST){
375
-				LOG(L_CRIT, "BUG: comp_str: bad type %d, "
376
-						"string expected\n", subtype);
375
+			if (rtype!=STRING_ST){
376
+				LOG(L_CRIT, "BUG: comp_string: bad type %d, "
377
+						"string expected\n", rtype);
377 378
 				goto error;
378 379
 			}
379
-			ret=(strcasecmp(str, (char*)param)==0);
380
+			ret=(strcasecmp(left, r->str.s)==0);
380 381
 			break;
381 382
 		case DIFF_OP:
382
-			if (subtype!=STRING_ST){
383
-				LOG(L_CRIT, "BUG: comp_str: bad type %d, "
384
-						"string expected\n", subtype);
383
+			if (rtype!=STRING_ST){
384
+				LOG(L_CRIT, "BUG: comp_string: bad type %d, "
385
+						"string expected\n", rtype);
385 386
 				goto error;
386 387
 			}
387
-			ret=(strcasecmp(str, (char*)param)!=0);
388
+			ret=(strcasecmp(left, r->str.s)!=0);
388 389
 			break;
389 390
 		case MATCH_OP:
390
-			if (subtype!=RE_ST){
391
-				LOG(L_CRIT, "BUG: comp_str: bad type %d, "
392
-						" RE expected\n", subtype);
391
+			if (rtype!=RE_ST){
392
+				LOG(L_CRIT, "BUG: comp_string: bad type %d, "
393
+						" RE expected\n", rtype);
393 394
 				goto error;
394 395
 			}
395
-			ret=(regexec((regex_t*)param, str, 0, 0, 0)==0);
396
+			ret=(regexec(r->re, left, 0, 0, 0)==0);
396 397
 			break;
397 398
 		default:
398
-			LOG(L_CRIT, "BUG: comp_str: unknown op %d\n", op);
399
+			LOG(L_CRIT, "BUG: comp_string: unknown op %d\n", op);
399 400
 			goto error;
400 401
 	}
401 402
 	return ret;
... ...
@@ -405,6 +491,42 @@ error:
405 405
 }
406 406
 
407 407
 
408
+inline static int comp_avp(int op, avp_spec_t* spec, int rtype, union exp_op* r)
409
+{
410
+	avp_t* avp;
411
+	int_str val;
412
+
413
+	avp = search_first_avp(spec->type, spec->name, &val, 0);
414
+	if (!avp) return 0;
415
+
416
+	switch(op) {
417
+	case NO_OP:
418
+		if (avp->flags & AVP_VAL_STR) {
419
+			return val.s.len;
420
+		} else {
421
+			return val.n != 0;
422
+		}
423
+		break;
424
+
425
+	case BINOR_OP:
426
+		return val.n | r->intval;
427
+		break;
428
+
429
+	case BINAND_OP:
430
+		return val.n & r->intval;
431
+		break;
432
+	}
433
+
434
+	if (avp->flags & AVP_VAL_STR) {
435
+		return comp_str(op, &val.s, rtype, r);
436
+	} else {
437
+		return comp_num(op, val.n, rtype, r);
438
+	}
439
+}
440
+
441
+
442
+
443
+
408 444
 /* check_self wrapper -- it checks also for the op */
409 445
 inline static int check_self_op(int op, str* s, unsigned short p)
410 446
 {
... ...
@@ -426,7 +548,7 @@ inline static int check_self_op(int op, str* s, unsigned short p)
426 426
 
427 427
 
428 428
 /* eval_elem helping function, returns an op param */
429
-inline static int comp_ip(struct ip_addr* ip, void* param, int op, int subtype)
429
+inline static int comp_ip(int op, struct ip_addr* ip, int rtype, union exp_op* r)
430 430
 {
431 431
 	struct hostent* he;
432 432
 	char ** h;
... ...
@@ -434,14 +556,14 @@ inline static int comp_ip(struct ip_addr* ip, void* param, int op, int subtype)
434 434
 	str tmp;
435 435
 
436 436
 	ret=-1;
437
-	switch(subtype){
437
+	switch(rtype){
438 438
 		case NET_ST:
439 439
 			switch(op){
440 440
 				case EQUAL_OP:
441
-					ret=(matchnet(ip, (struct net*) param)==1);
441
+					ret=(matchnet(ip, r->net)==1);
442 442
 					break;
443 443
 				case DIFF_OP:
444
-					ret=(matchnet(ip, (struct net*) param)!=1);
444
+					ret=(matchnet(ip, r->net)!=1);
445 445
 					break;
446 446
 				default:
447 447
 					goto error_op;
... ...
@@ -453,14 +575,14 @@ inline static int comp_ip(struct ip_addr* ip, void* param, int op, int subtype)
453 453
 				case EQUAL_OP:
454 454
 				case MATCH_OP:
455 455
 					/* 1: compare with ip2str*/
456
-					ret=comp_str(ip_addr2a(ip), param, op, subtype);
456
+					ret=comp_string(op, ip_addr2a(ip), rtype, r);
457 457
 					if (ret==1) break;
458 458
 					/* 2: resolve (name) & compare w/ all the ips */
459
-					if (subtype==STRING_ST){
460
-						he=resolvehost((char*)param);
459
+					if (rtype==STRING_ST){
460
+						he=resolvehost(r->str.s);
461 461
 						if (he==0){
462 462
 							DBG("comp_ip: could not resolve %s\n",
463
-									(char*)param);
463
+							    r->str.s);
464 464
 						}else if (he->h_addrtype==ip->af){
465 465
 							for(h=he->h_addr_list;(ret!=1)&& (*h); h++){
466 466
 								ret=(memcmp(ip->u.addr, *h, ip->len)==0);
... ...
@@ -478,15 +600,15 @@ inline static int comp_ip(struct ip_addr* ip, void* param, int op, int subtype)
478 478
 					ret=0;
479 479
 					}else{
480 480
 						/*  compare with primary host name */
481
-						ret=comp_str(he->h_name, param, op, subtype);
481
+						ret=comp_string(op, he->h_name, rtype, r);
482 482
 						/* compare with all the aliases */
483 483
 						for(h=he->h_aliases; (ret!=1) && (*h); h++){
484
-							ret=comp_str(*h, param, op, subtype);
484
+							ret=comp_string(op, *h, rtype, r);
485 485
 						}
486 486
 					}
487 487
 					break;
488 488
 				case DIFF_OP:
489
-					ret=comp_ip(ip, param, EQUAL_OP, subtype);
489
+					ret=comp_ip(EQUAL_OP, ip, rtype, r);
490 490
 					if (ret>=0) ret=!ret;
491 491
 					break;
492 492
 				default:
... ...
@@ -500,7 +622,7 @@ inline static int comp_ip(struct ip_addr* ip, void* param, int op, int subtype)
500 500
 			break;
501 501
 		default:
502 502
 			LOG(L_CRIT, "BUG: comp_ip: invalid type for "
503
-						" src_ip or dst_ip (%d)\n", subtype);
503
+						" src_ip or dst_ip (%d)\n", rtype);
504 504
 			ret=-1;
505 505
 	}
506 506
 	return ret;
... ...
@@ -511,11 +633,9 @@ error_op:
511 511
 }
512 512
 
513 513
 
514
-
515 514
 /* returns: 0/1 (false/true) or -1 on error, -127 EXPR_DROP */
516 515
 static int eval_elem(struct expr* e, struct sip_msg* msg)
517 516
 {
518
-
519 517
 	struct sip_uri uri;
520 518
 	int ret;
521 519
 	ret=E_BUG;
... ...
@@ -524,110 +644,127 @@ static int eval_elem(struct expr* e, struct sip_msg* msg)
524 524
 		LOG(L_CRIT," BUG: eval_elem: invalid type\n");
525 525
 		goto error;
526 526
 	}
527
-	switch(e->l.operand){
528
-		case METHOD_O:
529
-				ret=comp_strstr(&msg->first_line.u.request.method, e->r.param,
530
-								e->op, e->subtype);
531
-				break;
532
-		case URI_O:
533
-				if(msg->new_uri.s){
534
-					if (e->subtype==MYSELF_ST){
535
-						if (parse_sip_msg_uri(msg)<0) ret=-1;
536
-						else	ret=check_self_op(e->op, &msg->parsed_uri.host,
537
-									msg->parsed_uri.port_no?
538
-									msg->parsed_uri.port_no:SIP_PORT);
539
-					}else{
540
-						ret=comp_strstr(&msg->new_uri, e->r.param,
541
-										e->op, e->subtype);
542
-					}
543
-				}else{
544
-					if (e->subtype==MYSELF_ST){
545
-						if (parse_sip_msg_uri(msg)<0) ret=-1;
546
-						else	ret=check_self_op(e->op, &msg->parsed_uri.host,
547
-									msg->parsed_uri.port_no?
548
-									msg->parsed_uri.port_no:SIP_PORT);
549
-					}else{
550
-						ret=comp_strstr(&msg->first_line.u.request.uri,
551
-										 e->r.param, e->op, e->subtype);
552
-					}
553
-				}
554
-				break;
555
-		case FROM_URI_O:
556
-				if (parse_from_header(msg)!=0){
557
-					LOG(L_ERR, "ERROR: eval_elem: bad or missing"
558
-								" From: header\n");
559
-					goto error;
560
-				}
561
-				if (e->subtype==MYSELF_ST){
562
-					if (parse_uri(get_from(msg)->uri.s, get_from(msg)->uri.len,
563
-									&uri) < 0){
564
-						LOG(L_ERR, "ERROR: eval_elem: bad uri in From:\n");
565
-						goto error;
566
-					}
567
-					ret=check_self_op(e->op, &uri.host,
568
-										uri.port_no?uri.port_no:SIP_PORT);
569
-				}else{
570
-					ret=comp_strstr(&get_from(msg)->uri,
571
-							e->r.param, e->op, e->subtype);
572
-				}
573
-				break;
574
-		case TO_URI_O:
575
-				if ((msg->to==0) && ((parse_headers(msg, HDR_TO_F, 0)==-1) ||
576
-							(msg->to==0))){
577
-					LOG(L_ERR, "ERROR: eval_elem: bad or missing"
578
-								" To: header\n");
579
-					goto error;
580
-				}
581
-				/* to content is parsed automatically */
582
-				if (e->subtype==MYSELF_ST){
583
-					if (parse_uri(get_to(msg)->uri.s, get_to(msg)->uri.len,
584
-									&uri) < 0){
585
-						LOG(L_ERR, "ERROR: eval_elem: bad uri in To:\n");
586
-						goto error;
587
-					}
588
-					ret=check_self_op(e->op, &uri.host,
589
-										uri.port_no?uri.port_no:SIP_PORT);
590
-				}else{
591
-					ret=comp_strstr(&get_to(msg)->uri,
592
-										e->r.param, e->op, e->subtype);
593
-				}
594
-				break;
595
-		case SRCIP_O:
596
-				ret=comp_ip(&msg->rcv.src_ip, e->r.param, e->op, e->subtype);
597
-				break;
598
-		case DSTIP_O:
599
-				ret=comp_ip(&msg->rcv.dst_ip, e->r.param, e->op, e->subtype);
600
-				break;
601
-		case NUMBER_O:
602
-				ret=!(!e->r.intval); /* !! to transform it in {0,1} */
603
-				break;
604
-		case ACTION_O:
605
-				ret=run_actions( (struct action*)e->r.param, msg);
606
-				if (ret<=0) ret=(ret==0)?EXPR_DROP:0;
607
-				else ret=1;
608
-				break;
609
-		case SRCPORT_O:
610
-				ret=comp_no(msg->rcv.src_port, 
611
-					e->r.param, /* e.g., 5060 */
612
-					e->op, /* e.g. == */
613
-					e->subtype /* 5060 is number */);
614
-				break;
615
-		case DSTPORT_O:
616
-				ret=comp_no(msg->rcv.dst_port, e->r.param, e->op, 
617
-							e->subtype);
618
-				break;
619
-		case PROTO_O:
620
-				ret=comp_no(msg->rcv.proto, e->r.param, e->op, e->subtype);
621
-				break;
622
-		case AF_O:
623
-				ret=comp_no(msg->rcv.src_ip.af, e->r.param, e->op, e->subtype);
624
-				break;
625
-		case MSGLEN_O:
626
-				ret=comp_no(msg->len, e->r.param, e->op, e->subtype);
627
-				break;
628
-		default:
629
-				LOG(L_CRIT, "BUG: eval_elem: invalid operand %d\n",
630
-							e->l.operand);
527
+	switch(e->l_type){
528
+	case METHOD_O:
529
+		ret=comp_str(e->op, &msg->first_line.u.request.method, 
530
+			     e->r_type, &e->r);
531
+		break;
532
+	case URI_O:
533
+		if(msg->new_uri.s) {
534
+			if (e->r_type==MYSELF_ST){
535
+				if (parse_sip_msg_uri(msg)<0) ret=-1;
536
+				else ret=check_self_op(e->op, &msg->parsed_uri.host,
537
+						       msg->parsed_uri.port_no?
538
+						       msg->parsed_uri.port_no:SIP_PORT);
539
+			}else{
540
+				ret=comp_str(e->op, &msg->new_uri, 
541
+					     e->r_type, &e->r);
542
+			}
543
+		}else{
544
+			if (e->r_type==MYSELF_ST){
545
+				if (parse_sip_msg_uri(msg)<0) ret=-1;
546
+				else ret=check_self_op(e->op, &msg->parsed_uri.host,
547
+						       msg->parsed_uri.port_no?
548
+						       msg->parsed_uri.port_no:SIP_PORT);
549
+			}else{
550
+				ret=comp_str(e->op, &msg->first_line.u.request.uri,
551
+					     e->r_type, &e->r);
552
+			}
553
+		}
554
+		break;
555
+		
556
+	case FROM_URI_O:
557
+		if (parse_from_header(msg)!=0){
558
+			LOG(L_ERR, "ERROR: eval_elem: bad or missing"
559
+			    " From: header\n");
560
+			goto error;
561
+		}
562
+		if (e->r_type==MYSELF_ST){
563
+			if (parse_uri(get_from(msg)->uri.s, get_from(msg)->uri.len,
564
+				      &uri) < 0){
565
+				LOG(L_ERR, "ERROR: eval_elem: bad uri in From:\n");
566
+				goto error;
567
+			}
568
+			ret=check_self_op(e->op, &uri.host,
569
+					  uri.port_no?uri.port_no:SIP_PORT);
570
+		}else{
571
+			ret=comp_str(e->op, &get_from(msg)->uri,
572
+				     e->r_type, &e->r);
573
+		}
574
+		break;
575
+
576
+	case TO_URI_O:
577
+		if ((msg->to==0) && ((parse_headers(msg, HDR_TO_F, 0)==-1) ||
578
+				     (msg->to==0))){
579
+			LOG(L_ERR, "ERROR: eval_elem: bad or missing"
580
+			    " To: header\n");
581
+			goto error;
582
+		}
583
+		     /* to content is parsed automatically */
584
+		if (e->r_type==MYSELF_ST){
585
+			if (parse_uri(get_to(msg)->uri.s, get_to(msg)->uri.len,
586
+				      &uri) < 0){
587
+				LOG(L_ERR, "ERROR: eval_elem: bad uri in To:\n");
588
+				goto error;
589
+			}
590
+			ret=check_self_op(e->op, &uri.host,
591
+					  uri.port_no?uri.port_no:SIP_PORT);
592
+		}else{
593
+			ret=comp_str(e->op, &get_to(msg)->uri,
594
+				     e->r_type, &e->r);
595
+		}
596
+		break;
597
+		
598
+	case SRCIP_O:
599
+		ret=comp_ip(e->op, &msg->rcv.src_ip, e->r_type, &e->r);
600
+		break;
601
+		
602
+	case DSTIP_O:
603
+		ret=comp_ip(e->op, &msg->rcv.dst_ip, e->r_type, &e->r);
604
+		break;
605
+
606
+	case NUMBER_O:
607
+		ret=!(!e->r.intval); /* !! to transform it in {0,1} */
608
+		break;
609
+
610
+	case ACTION_O:
611
+		ret=run_actions( (struct action*)e->r.param, msg);
612
+		if (ret<=0) ret=(ret==0)?EXPR_DROP:0;
613
+		else ret=1;
614
+		break;
615
+		
616
+	case SRCPORT_O:
617
+		ret=comp_num(e->op, (int)msg->rcv.src_port, 
618
+			     e->r_type, &e->r);
619
+		break;
620
+		
621
+	case DSTPORT_O:
622
+		ret=comp_num(e->op, (int)msg->rcv.dst_port, 
623
+			     e->r_type, &e->r);
624
+		break;
625
+		
626
+	case PROTO_O:
627
+		ret=comp_num(e->op, msg->rcv.proto, 
628
+			     e->r_type, &e->r);
629
+		break;
630
+		
631
+	case AF_O:
632
+		ret=comp_num(e->op, (int)msg->rcv.src_ip.af, 
633
+			     e->r_type, &e->r);
634
+		break;
635
+
636
+	case MSGLEN_O:
637
+		ret=comp_num(e->op, (int)msg->len, 
638
+				e->r_type, &e->r);
639
+		break;
640
+
641
+	case AVP_ST:
642
+		ret = comp_avp(e->op, e->l.attr, e->r_type, &e->r);
643
+		break;
644
+		
645
+	default:
646
+		LOG(L_CRIT, "BUG: eval_elem: invalid operand %d\n",
647
+		    e->l_type);
631 648
 	}
632 649
 	return ret;
633 650
 error:
... ...
@@ -654,13 +791,13 @@ int eval_expr(struct expr* e, struct sip_msg* msg)
654 654
 		ret=eval_elem(e, msg);
655 655
 	}else if (e->type==EXP_T){
656 656
 		switch(e->op){
657
-			case AND_OP:
657
+			case LOGAND_OP:
658 658
 				ret=eval_expr(e->l.expr, msg);
659 659
 				/* if error or false stop evaluating the rest */
660 660
 				if (ret!=1) break;
661 661
 				ret=eval_expr(e->r.expr, msg); /*ret1 is 1*/
662 662
 				break;
663
-			case OR_OP:
663
+			case LOGOR_OP:
664 664
 				ret=eval_expr(e->l.expr, msg);
665 665
 				/* if true or error stop evaluating the rest */
666 666
 				if (ret!=0) break;
... ...
@@ -756,8 +893,7 @@ int fix_rls()
756 756
 /* debug function, prints main routing table */
757 757
 void print_rl()
758 758
 {
759
-	struct action* t;
760
-	int i,j;
759
+	int j;
761 760
 
762 761
 	for(j=0; j<RT_NO; j++){
763 762
 		if (rlist[j]==0){
... ...
@@ -765,9 +901,7 @@ void print_rl()
765 765
 			continue;
766 766
 		}
767 767
 		DBG("routing table %d:\n",j);
768
-		for (t=rlist[j],i=0; t; i++, t=t->next){
769
-			print_action(t);
770
-		}
768
+		print_actions(rlist[j]);
771 769
 		DBG("\n");
772 770
 	}
773 771
 	for(j=0; j<ONREPLY_RT_NO; j++){
... ...
@@ -775,9 +909,7 @@ void print_rl()
775 775
 			continue;
776 776
 		}
777 777
 		DBG("onreply routing table %d:\n",j);
778
-		for (t=onreply_rlist[j],i=0; t; i++, t=t->next){
779
-			print_action(t);
780
-		}
778
+		print_actions(onreply_rlist[j]);
781 779
 		DBG("\n");
782 780
 	}
783 781
 	for(j=0; j<FAILURE_RT_NO; j++){
... ...
@@ -785,9 +917,7 @@ void print_rl()
785 785
 			continue;
786 786
 		}
787 787
 		DBG("failure routing table %d:\n",j);
788
-		for (t=failure_rlist[j],i=0; t; i++, t=t->next){
789
-			print_action(t);
790
-		}
788
+		print_actions(failure_rlist[j]);
791 789
 		DBG("\n");
792 790
 	}
793 791
 	for(j=0; j<BRANCH_RT_NO; j++){
... ...
@@ -795,9 +925,7 @@ void print_rl()
795 795
 			continue;
796 796
 		}
797 797
 		DBG("branch routing table %d:\n",j);
798
-		for (t=branch_rlist[j],i=0; t; i++, t=t->next){
799
-			print_action(t);
800
-		}
798
+		print_actions(branch_rlist[j]);
801 799
 		DBG("\n");
802 800
 	}
803 801
 }
... ...
@@ -46,6 +46,7 @@
46 46
 #include "dprint.h"
47 47
 #include "ip_addr.h"
48 48
 #include "mem/mem.h"
49
+#include "usr_avp.h"
49 50
 #include "ut.h" /* ZSW() */
50 51
 
51 52
 
... ...
@@ -65,16 +66,17 @@ error:
65 65
 }
66 66
 
67 67
 
68
-struct expr* mk_elem(int op, int subtype, int operand, void* param)
68
+struct expr* mk_elem(int op, int ltype, void* lparam, int rtype, void* rparam)
69 69
 {
70 70
 	struct expr * e;
71 71
 	e=(struct expr*)pkg_malloc(sizeof (struct expr));
72 72
 	if (e==0) goto error;
73 73
 	e->type=ELEM_T;
74 74
 	e->op=op;
75
-	e->subtype=subtype;
76
-	e->l.operand=operand;
77
-	e->r.param=param;
75
+	e->l_type=ltype;
76
+	e->l.param=lparam;
77
+	e->r_type = rtype;
78
+	e->r.param=rparam;
78 79
 	return e;
79 80
 error:
80 81
 	LOG(L_CRIT, "ERROR: mk_elem: memory allocation failure\n");
... ...
@@ -84,7 +86,7 @@ error:
84 84
 
85 85
 
86 86
 struct action* mk_action(int type, int p1_type, int p2_type,
87
-											void* p1, void* p2)
87
+			 void* p1, void* p2)
88 88
 {
89 89
 	struct action* a;
90 90
 	a=(struct action*)pkg_malloc(sizeof(struct action));
... ...
@@ -140,7 +142,7 @@ void print_expr(struct expr* exp)
140 140
 		return;
141 141
 	}
142 142
 	if (exp->type==ELEM_T){
143
-		switch(exp->l.operand){
143
+		switch(exp->l_type){
144 144
 			case METHOD_O:
145 145
 				DBG("method");
146 146
 				break;
... ...
@@ -169,6 +171,10 @@ void print_expr(struct expr* exp)
169 169
 				break;
170 170
 			case ACTION_O:
171 171
 				break;
172
+		        case AVP_ST:
173
+				DBG("attr");
174
+				break;
175
+			
172 176
 			default:
173 177
 				DBG("UNKNOWN");
174 178
 		}
... ...
@@ -199,7 +205,7 @@ void print_expr(struct expr* exp)
199 199
 			default:
200 200
 				DBG("<UNKNOWN>");
201 201
 		}
202
-		switch(exp->subtype){
202
+		switch(exp->r_type){
203 203
 			case NOSUBTYPE: 
204 204
 					DBG("N/A");
205 205
 					break;
... ...
@@ -213,7 +219,7 @@ void print_expr(struct expr* exp)
213 213
 					print_ip("", (struct ip_addr*)exp->r.param, "");
214 214
 					break;
215 215
 			case ACTIONS_ST:
216
-					print_action((struct action*)exp->r.param);
216
+					print_actions((struct action*)exp->r.param);
217 217
 					break;
218 218
 			case NUMBER_ST:
219 219
 					DBG("%d",exp->r.intval);
... ...
@@ -221,19 +227,23 @@ void print_expr(struct expr* exp)
221 221
 			case MYSELF_ST:
222 222
 					DBG("_myself_");
223 223
 					break;
224
+		        case AVP_ST:
225
+				DBG("attr");
226
+				break;
227
+			
224 228
 			default:
225
-					DBG("type<%d>", exp->subtype);
229
+					DBG("type<%d>", exp->r_type);
226 230
 		}
227 231
 	}else if (exp->type==EXP_T){
228 232
 		switch(exp->op){
229
-			case AND_OP:
233
+			case LOGAND_OP:
230 234
 					DBG("AND( ");
231 235
 					print_expr(exp->l.expr);
232 236
 					DBG(", ");
233 237
 					print_expr(exp->r.expr);
234 238
 					DBG(" )");
235 239
 					break;
236
-			case OR_OP:
240
+			case LOGOR_OP:
237 241
 					DBG("OR( ");
238 242
 					print_expr(exp->l.expr);
239 243
 					DBG(", ");
... ...
@@ -257,201 +267,214 @@ void print_expr(struct expr* exp)
257 257
 
258 258
 					
259 259
 
260
-void print_action(struct action* a)
260
+void print_action(struct action* t)
261 261
 {
262
-	struct action* t;
263
-	for(t=a; t!=0;t=t->next){
264
-		switch(t->type){
265
-			case FORWARD_T:
266
-					DBG("forward(");
267
-					break;
268
-			case FORWARD_TCP_T:
269
-					DBG("forward_tcp(");
270
-					break;
271
-			case FORWARD_UDP_T:
272
-					DBG("forward_udp(");
273
-					break;
274
-			case SEND_T:
275
-					DBG("send(");
276
-					break;
277
-			case SEND_TCP_T:
278
-					DBG("send_tcp(");
279
-					break;
280
-			case DROP_T:
281
-					DBG("drop(");
282
-					break;
283
-			case LOG_T:
284
-					DBG("log(");
285
-					break;
286
-			case ERROR_T:
287
-					DBG("error(");
288
-					break;
289
-			case ROUTE_T:
290
-					DBG("route(");
291
-					break;
292