]> git.ipfire.org Git - thirdparty/dhcp.git/blob - server/class.c
Merge changes between 3.0rc7 and 3.0rc8pl2.
[thirdparty/dhcp.git] / server / class.c
1 /* class.c
2
3 Handling for client classes. */
4
5 /*
6 * Copyright (c) 1998-2001 Internet Software Consortium.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
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.
21 *
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
34 * SUCH DAMAGE.
35 *
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''.
42 */
43
44 #ifndef lint
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";
47
48 #endif /* not lint */
49
50 #include "dhcpd.h"
51
52 struct collection default_collection = {
53 (struct collection *)0,
54 "default",
55 (struct class *)0,
56 };
57
58 struct collection *collections = &default_collection;
59 struct executable_statement *default_classification_rules;
60
61 int have_billing_classes;
62
63 /* Build the default classification rule tree. */
64
65 void classification_setup ()
66 {
67 /* eval ... */
68 default_classification_rules = (struct executable_statement *)0;
69 if (!executable_statement_allocate (&default_classification_rules,
70 MDL))
71 log_fatal ("Can't allocate check of default collection");
72 default_classification_rules -> op = eval_statement;
73
74 /* check-collection "default" */
75 if (!expression_allocate (&default_classification_rules -> data.eval,
76 MDL))
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 =
80 &default_collection;
81 }
82
83 void classify_client (packet)
84 struct packet *packet;
85 {
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);
90 }
91
92 int check_collection (packet, lease, collection)
93 struct packet *packet;
94 struct lease *lease;
95 struct collection *collection;
96 {
97 struct class *class, *nc;
98 struct data_string data;
99 int matched = 0;
100 int status;
101 int ignorep;
102
103 for (class = collection -> classes; class; class = class -> nic) {
104 #if defined (DEBUG_CLASS_MATCHING)
105 log_info ("checking against class %s...", class -> name);
106 #endif
107 memset (&data, 0, sizeof data);
108
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. */
114
115 if (class -> expr) {
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,
121 class -> expr));
122 if (status) {
123 if (!class -> submatch) {
124 matched = 1;
125 #if defined (DEBUG_CLASS_MATCHING)
126 log_info ("matches class.");
127 #endif
128 classify (packet, class);
129 continue;
130 }
131 } else
132 continue;
133 }
134
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,
149 data.len, MDL)) {
150 #if defined (DEBUG_CLASS_MATCHING)
151 log_info ("matches subclass %s.",
152 print_hex_1 (data.len,
153 data.data, 60));
154 #endif
155 data_string_forget (&data, MDL);
156 classify (packet, nc);
157 matched = 1;
158 class_dereference (&nc, MDL);
159 continue;
160 }
161 if (!class -> spawning) {
162 data_string_forget (&data, MDL);
163 continue;
164 }
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));
169 #endif
170 status = class_allocate (&nc, MDL);
171 group_reference (&nc -> group,
172 class -> group, MDL);
173 class_reference (&nc -> superclass,
174 class, MDL);
175 nc -> lease_limit = class -> lease_limit;
176 nc -> dirty = 1;
177 if (nc -> lease_limit) {
178 nc -> billed_leases =
179 (dmalloc
180 (nc -> lease_limit *
181 sizeof (struct lease *),
182 MDL));
183 if (!nc -> billed_leases) {
184 log_error ("no memory for%s",
185 " billing");
186 data_string_forget
187 (&nc -> hash_string,
188 MDL);
189 class_dereference (&nc, MDL);
190 data_string_forget (&data,
191 MDL);
192 continue;
193 }
194 memset (nc -> billed_leases, 0,
195 (nc -> lease_limit *
196 sizeof nc -> billed_leases));
197 }
198 data_string_copy (&nc -> hash_string, &data,
199 MDL);
200 data_string_forget (&data, MDL);
201 if (!class -> hash)
202 class -> hash = new_hash (0, 0, 0, MDL);
203 class_hash_add (class -> hash,
204 (const char *)
205 nc -> hash_string.data,
206 nc -> hash_string.len,
207 nc, MDL);
208 classify (packet, nc);
209 class_dereference (&nc, MDL);
210 }
211 }
212 }
213 return matched;
214 }
215
216 void classify (packet, class)
217 struct packet *packet;
218 struct class *class;
219 {
220 if (packet -> class_count < PACKET_MAX_CLASSES)
221 class_reference (&packet -> classes [packet -> class_count++],
222 class, MDL);
223 else
224 log_error ("too many classes match %s",
225 print_hw_addr (packet -> raw -> htype,
226 packet -> raw -> hlen,
227 packet -> raw -> chaddr));
228 }
229
230
231 isc_result_t unlink_class(struct class **class) {
232 struct collection *lp;
233 struct class *cp, *pp;
234
235 for (lp = collections; lp; lp = lp -> next) {
236 for (pp = 0, cp = lp -> classes; cp; pp = cp, cp = cp -> nic)
237 if (cp == *class) {
238 if (pp == 0) {
239 lp->classes = cp->nic;
240 } else {
241 pp->nic = cp->nic;
242 }
243 cp->nic = 0;
244 class_dereference(class, MDL);
245
246 return ISC_R_SUCCESS;
247 }
248 }
249 return ISC_R_NOTFOUND;
250 }
251
252
253 isc_result_t find_class (struct class **class, const char *name,
254 const char *file, int line)
255 {
256 struct collection *lp;
257 struct class *cp;
258
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);
263 }
264 }
265 return ISC_R_NOTFOUND;
266 }
267
268 int unbill_class (lease, class)
269 struct lease *lease;
270 struct class *class;
271 {
272 int i;
273
274 for (i = 0; i < class -> lease_limit; i++)
275 if (class -> billed_leases [i] == lease)
276 break;
277 if (i == class -> lease_limit) {
278 log_error ("lease %s unbilled with no billing arrangement.",
279 piaddr (lease -> ip_addr));
280 return 0;
281 }
282 class_dereference (&lease -> billing_class, MDL);
283 lease_dereference (&class -> billed_leases [i], MDL);
284 class -> leases_consumed--;
285 return 1;
286 }
287
288 int bill_class (lease, class)
289 struct lease *lease;
290 struct class *class;
291 {
292 int i;
293
294 if (lease -> billing_class) {
295 log_error ("lease billed with existing billing arrangement.");
296 unbill_class (lease, lease -> billing_class);
297 }
298
299 if (class -> leases_consumed == class -> lease_limit)
300 return 0;
301
302 for (i = 0; i < class -> lease_limit; i++)
303 if (!class -> billed_leases [i])
304 break;
305
306 if (i == class -> lease_limit) {
307 log_error ("class billing consumption disagrees with leases.");
308 return 0;
309 }
310
311 lease_reference (&class -> billed_leases [i], lease, MDL);
312 class_reference (&lease -> billing_class, class, MDL);
313 class -> leases_consumed++;
314 return 1;
315 }