3 Handling for client classes. */
6 * Copyright (c) 1998-2001 Internet Software Consortium.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 * of its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * This software has been written for the Internet Software Consortium
37 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
38 * To learn more about the Internet Software Consortium, see
39 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
40 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
41 * ``http://www.nominum.com''.
45 static char copyright
[] =
46 "$Id: class.c,v 1.31 2001/06/27 00:31:02 mellon Exp $ Copyright (c) 1998-2001 The Internet Software Consortium. All rights reserved.\n";
52 struct collection default_collection
= {
53 (struct collection
*)0,
58 struct collection
*collections
= &default_collection
;
59 struct executable_statement
*default_classification_rules
;
61 int have_billing_classes
;
63 /* Build the default classification rule tree. */
65 void classification_setup ()
68 default_classification_rules
= (struct executable_statement
*)0;
69 if (!executable_statement_allocate (&default_classification_rules
,
71 log_fatal ("Can't allocate check of default collection");
72 default_classification_rules
-> op
= eval_statement
;
74 /* check-collection "default" */
75 if (!expression_allocate (&default_classification_rules
-> data
.eval
,
77 log_fatal ("Can't allocate default check expression");
78 default_classification_rules
-> data
.eval
-> op
= expr_check
;
79 default_classification_rules
-> data
.eval
-> data
.check
=
83 void classify_client (packet
)
84 struct packet
*packet
;
86 execute_statements ((struct binding_value
**)0, packet
,
87 (struct lease
*)0, (struct client_state
*)0,
88 packet
-> options
, (struct option_state
*)0,
89 &global_scope
, default_classification_rules
);
92 int check_collection (packet
, lease
, collection
)
93 struct packet
*packet
;
95 struct collection
*collection
;
97 struct class *class, *nc
;
98 struct data_string data
;
103 for (class = collection
-> classes
; class; class = class -> nic
) {
104 #if defined (DEBUG_CLASS_MATCHING)
105 log_info ("checking against class %s...", class -> name
);
107 memset (&data
, 0, sizeof data
);
109 /* If there is a "match if" expression, check it. If
110 we get a match, and there's no subclass expression,
111 it's a match. If we get a match and there is a subclass
112 expression, then we check the submatch. If it's not a
113 match, that's final - we don't check the submatch. */
116 status
= (evaluate_boolean_expression_result
117 (&ignorep
, packet
, lease
,
118 (struct client_state
*)0,
119 packet
-> options
, (struct option_state
*)0,
120 lease
? &lease
-> scope
: &global_scope
,
123 if (!class -> submatch
) {
125 #if defined (DEBUG_CLASS_MATCHING)
126 log_info ("matches class.");
128 classify (packet
, class);
135 /* Check to see if the client matches an existing subclass.
136 If it doesn't, and this is a spawning class, spawn a new
137 subclass and put the client in it. */
138 if (class -> submatch
) {
139 status
= (evaluate_data_expression
140 (&data
, packet
, lease
,
141 (struct client_state
*)0,
142 packet
-> options
, (struct option_state
*)0,
143 lease
? &lease
-> scope
: &global_scope
,
144 class -> submatch
, MDL
));
145 if (status
&& data
.len
) {
146 nc
= (struct class *)0;
147 if (class_hash_lookup (&nc
, class -> hash
,
148 (const char *)data
.data
,
150 #if defined (DEBUG_CLASS_MATCHING)
151 log_info ("matches subclass %s.",
152 print_hex_1 (data
.len
,
155 data_string_forget (&data
, MDL
);
156 classify (packet
, nc
);
158 class_dereference (&nc
, MDL
);
161 if (!class -> spawning
) {
162 data_string_forget (&data
, MDL
);
165 /* XXX Write out the spawned class? */
166 #if defined (DEBUG_CLASS_MATCHING)
167 log_info ("spawning subclass %s.",
168 print_hex_1 (data
.len
, data
.data
, 60));
170 status
= class_allocate (&nc
, MDL
);
171 group_reference (&nc
-> group
,
172 class -> group
, MDL
);
173 class_reference (&nc
-> superclass
,
175 nc
-> lease_limit
= class -> lease_limit
;
177 if (nc
-> lease_limit
) {
178 nc
-> billed_leases
=
181 sizeof (struct lease
*),
183 if (!nc
-> billed_leases
) {
184 log_error ("no memory for%s",
189 class_dereference (&nc
, MDL
);
190 data_string_forget (&data
,
194 memset (nc
-> billed_leases
, 0,
196 sizeof nc
-> billed_leases
));
198 data_string_copy (&nc
-> hash_string
, &data
,
200 data_string_forget (&data
, MDL
);
202 class -> hash
= new_hash (0, 0, 0, MDL
);
203 class_hash_add (class -> hash
,
205 nc
-> hash_string
.data
,
206 nc
-> hash_string
.len
,
208 classify (packet
, nc
);
209 class_dereference (&nc
, MDL
);
216 void classify (packet
, class)
217 struct packet
*packet
;
220 if (packet
-> class_count
< PACKET_MAX_CLASSES
)
221 class_reference (&packet
-> classes
[packet
-> class_count
++],
224 log_error ("too many classes match %s",
225 print_hw_addr (packet
-> raw
-> htype
,
226 packet
-> raw
-> hlen
,
227 packet
-> raw
-> chaddr
));
231 isc_result_t
unlink_class(struct class **class) {
232 struct collection
*lp
;
233 struct class *cp
, *pp
;
235 for (lp
= collections
; lp
; lp
= lp
-> next
) {
236 for (pp
= 0, cp
= lp
-> classes
; cp
; pp
= cp
, cp
= cp
-> nic
)
239 lp
->classes
= cp
->nic
;
244 class_dereference(class, MDL
);
246 return ISC_R_SUCCESS
;
249 return ISC_R_NOTFOUND
;
253 isc_result_t
find_class (struct class **class, const char *name
,
254 const char *file
, int line
)
256 struct collection
*lp
;
259 for (lp
= collections
; lp
; lp
= lp
-> next
) {
260 for (cp
= lp
-> classes
; cp
; cp
= cp
-> nic
)
261 if (cp
-> name
&& !strcmp (name
, cp
-> name
)) {
262 return class_reference (class, cp
, file
, line
);
265 return ISC_R_NOTFOUND
;
268 int unbill_class (lease
, class)
274 for (i
= 0; i
< class -> lease_limit
; i
++)
275 if (class -> billed_leases
[i
] == lease
)
277 if (i
== class -> lease_limit
) {
278 log_error ("lease %s unbilled with no billing arrangement.",
279 piaddr (lease
-> ip_addr
));
282 class_dereference (&lease
-> billing_class
, MDL
);
283 lease_dereference (&class -> billed_leases
[i
], MDL
);
284 class -> leases_consumed
--;
288 int bill_class (lease
, class)
294 if (lease
-> billing_class
) {
295 log_error ("lease billed with existing billing arrangement.");
296 unbill_class (lease
, lease
-> billing_class
);
299 if (class -> leases_consumed
== class -> lease_limit
)
302 for (i
= 0; i
< class -> lease_limit
; i
++)
303 if (!class -> billed_leases
[i
])
306 if (i
== class -> lease_limit
) {
307 log_error ("class billing consumption disagrees with leases.");
311 lease_reference (&class -> billed_leases
[i
], lease
, MDL
);
312 class_reference (&lease
-> billing_class
, class, MDL
);
313 class -> leases_consumed
++;