3 Handling for client classes. */
6 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1998-2003 by Internet Software Consortium
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Internet Systems Consortium, Inc.
23 * Redwood City, CA 94063
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
36 static char copyright[] =
37 "$Id: class.c,v 1.29.2.4 2004/06/10 17:59:51 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
43 struct collection default_collection = {
44 (struct collection *)0,
49 struct collection *collections = &default_collection;
50 struct executable_statement *default_classification_rules;
52 int have_billing_classes;
54 /* Build the default classification rule tree. */
56 void classification_setup ()
59 default_classification_rules = (struct executable_statement *)0;
60 if (!executable_statement_allocate (&default_classification_rules,
62 log_fatal ("Can't allocate check of default collection");
63 default_classification_rules -> op = eval_statement;
65 /* check-collection "default" */
66 if (!expression_allocate (&default_classification_rules -> data.eval,
68 log_fatal ("Can't allocate default check expression");
69 default_classification_rules -> data.eval -> op = expr_check;
70 default_classification_rules -> data.eval -> data.check =
74 void classify_client (packet)
75 struct packet *packet;
77 execute_statements ((struct binding_value **)0, packet,
78 (struct lease *)0, (struct client_state *)0,
79 packet -> options, (struct option_state *)0,
80 &global_scope, default_classification_rules);
83 int check_collection (packet, lease, collection)
84 struct packet *packet;
86 struct collection *collection;
88 struct class *class, *nc;
89 struct data_string data;
94 for (class = collection -> classes; class; class = class -> nic) {
95 #if defined (DEBUG_CLASS_MATCHING)
96 log_info ("checking against class %s...", class -> name);
98 memset (&data, 0, sizeof data);
100 /* If there is a "match if" expression, check it. If
101 we get a match, and there's no subclass expression,
102 it's a match. If we get a match and there is a subclass
103 expression, then we check the submatch. If it's not a
104 match, that's final - we don't check the submatch. */
107 status = (evaluate_boolean_expression_result
108 (&ignorep, packet, lease,
109 (struct client_state *)0,
110 packet -> options, (struct option_state *)0,
111 lease ? &lease -> scope : &global_scope,
114 if (!class -> submatch) {
116 #if defined (DEBUG_CLASS_MATCHING)
117 log_info ("matches class.");
119 classify (packet, class);
126 /* Check to see if the client matches an existing subclass.
127 If it doesn't, and this is a spawning class, spawn a new
128 subclass and put the client in it. */
129 if (class -> submatch) {
130 status = (evaluate_data_expression
131 (&data, packet, lease,
132 (struct client_state *)0,
133 packet -> options, (struct option_state *)0,
134 lease ? &lease -> scope : &global_scope,
135 class -> submatch, MDL));
136 if (status && data.len) {
137 nc = (struct class *)0;
138 if (class_hash_lookup (&nc, class -> hash,
139 (const char *)data.data,
141 #if defined (DEBUG_CLASS_MATCHING)
142 log_info ("matches subclass %s.",
143 print_hex_1 (data.len,
146 data_string_forget (&data, MDL);
147 classify (packet, nc);
149 class_dereference (&nc, MDL);
152 if (!class -> spawning) {
153 data_string_forget (&data, MDL);
156 /* XXX Write out the spawned class? */
157 #if defined (DEBUG_CLASS_MATCHING)
158 log_info ("spawning subclass %s.",
159 print_hex_1 (data.len, data.data, 60));
161 status = class_allocate (&nc, MDL);
162 group_reference (&nc -> group,
163 class -> group, MDL);
164 class_reference (&nc -> superclass,
166 nc -> lease_limit = class -> lease_limit;
168 if (nc -> lease_limit) {
169 nc -> billed_leases =
172 sizeof (struct lease *),
174 if (!nc -> billed_leases) {
175 log_error ("no memory for%s",
180 class_dereference (&nc, MDL);
181 data_string_forget (&data,
185 memset (nc -> billed_leases, 0,
187 sizeof nc -> billed_leases));
189 data_string_copy (&nc -> hash_string, &data,
191 data_string_forget (&data, MDL);
193 class_new_hash (&class -> hash, 0, MDL);
194 class_hash_add (class -> hash,
196 nc -> hash_string.data,
197 nc -> hash_string.len,
199 classify (packet, nc);
200 class_dereference (&nc, MDL);
207 void classify (packet, class)
208 struct packet *packet;
211 if (packet -> class_count < PACKET_MAX_CLASSES)
212 class_reference (&packet -> classes [packet -> class_count++],
215 log_error ("too many classes match %s",
216 print_hw_addr (packet -> raw -> htype,
217 packet -> raw -> hlen,
218 packet -> raw -> chaddr));
221 isc_result_t find_class (struct class **class, const char *name,
222 const char *file, int line)
224 struct collection *lp;
227 for (lp = collections; lp; lp = lp -> next) {
228 for (cp = lp -> classes; cp; cp = cp -> nic)
229 if (cp -> name && !strcmp (name, cp -> name)) {
230 return class_reference (class, cp, file, line);
233 return ISC_R_NOTFOUND;
236 int unbill_class (lease, class)
242 for (i = 0; i < class -> lease_limit; i++)
243 if (class -> billed_leases [i] == lease)
245 if (i == class -> lease_limit) {
246 log_error ("lease %s unbilled with no billing arrangement.",
247 piaddr (lease -> ip_addr));
250 class_dereference (&lease -> billing_class, MDL);
251 lease_dereference (&class -> billed_leases [i], MDL);
252 class -> leases_consumed--;
256 int bill_class (lease, class)
262 if (lease -> billing_class) {
263 log_error ("lease billed with existing billing arrangement.");
264 unbill_class (lease, lease -> billing_class);
267 if (class -> leases_consumed == class -> lease_limit)
270 for (i = 0; i < class -> lease_limit; i++)
271 if (!class -> billed_leases [i])
274 if (i == class -> lease_limit) {
275 log_error ("class billing consumption disagrees with leases.");
279 lease_reference (&class -> billed_leases [i], lease, MDL);
280 class_reference (&lease -> billing_class, class, MDL);
281 class -> leases_consumed++;