Fix sockopt syscalls for the Nth time.
[dragonfly.git] / contrib / dhcp-3.0 / server / class.c
blobcd5aec6223711b0bc8da06e388885120fae7b137
1 /* class.c
3 Handling for client classes. */
5 /*
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.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * http://www.isc.org/
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''.
35 #ifndef lint
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";
39 #endif /* not lint */
41 #include "dhcpd.h"
43 struct collection default_collection = {
44 (struct collection *)0,
45 "default",
46 (struct class *)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 ()
58 /* eval ... */
59 default_classification_rules = (struct executable_statement *)0;
60 if (!executable_statement_allocate (&default_classification_rules,
61 MDL))
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,
67 MDL))
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 =
71 &default_collection;
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;
85 struct lease *lease;
86 struct collection *collection;
88 struct class *class, *nc;
89 struct data_string data;
90 int matched = 0;
91 int status;
92 int ignorep;
94 for (class = collection -> classes; class; class = class -> nic) {
95 #if defined (DEBUG_CLASS_MATCHING)
96 log_info ("checking against class %s...", class -> name);
97 #endif
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. */
106 if (class -> expr) {
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,
112 class -> expr));
113 if (status) {
114 if (!class -> submatch) {
115 matched = 1;
116 #if defined (DEBUG_CLASS_MATCHING)
117 log_info ("matches class.");
118 #endif
119 classify (packet, class);
120 continue;
122 } else
123 continue;
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,
140 data.len, MDL)) {
141 #if defined (DEBUG_CLASS_MATCHING)
142 log_info ("matches subclass %s.",
143 print_hex_1 (data.len,
144 data.data, 60));
145 #endif
146 data_string_forget (&data, MDL);
147 classify (packet, nc);
148 matched = 1;
149 class_dereference (&nc, MDL);
150 continue;
152 if (!class -> spawning) {
153 data_string_forget (&data, MDL);
154 continue;
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));
160 #endif
161 status = class_allocate (&nc, MDL);
162 group_reference (&nc -> group,
163 class -> group, MDL);
164 class_reference (&nc -> superclass,
165 class, MDL);
166 nc -> lease_limit = class -> lease_limit;
167 nc -> dirty = 1;
168 if (nc -> lease_limit) {
169 nc -> billed_leases =
170 (dmalloc
171 (nc -> lease_limit *
172 sizeof (struct lease *),
173 MDL));
174 if (!nc -> billed_leases) {
175 log_error ("no memory for%s",
176 " billing");
177 data_string_forget
178 (&nc -> hash_string,
179 MDL);
180 class_dereference (&nc, MDL);
181 data_string_forget (&data,
182 MDL);
183 continue;
185 memset (nc -> billed_leases, 0,
186 (nc -> lease_limit *
187 sizeof nc -> billed_leases));
189 data_string_copy (&nc -> hash_string, &data,
190 MDL);
191 data_string_forget (&data, MDL);
192 if (!class -> hash)
193 class_new_hash (&class -> hash, 0, MDL);
194 class_hash_add (class -> hash,
195 (const char *)
196 nc -> hash_string.data,
197 nc -> hash_string.len,
198 nc, MDL);
199 classify (packet, nc);
200 class_dereference (&nc, MDL);
204 return matched;
207 void classify (packet, class)
208 struct packet *packet;
209 struct class *class;
211 if (packet -> class_count < PACKET_MAX_CLASSES)
212 class_reference (&packet -> classes [packet -> class_count++],
213 class, MDL);
214 else
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;
225 struct class *cp;
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)
237 struct lease *lease;
238 struct class *class;
240 int i;
242 for (i = 0; i < class -> lease_limit; i++)
243 if (class -> billed_leases [i] == lease)
244 break;
245 if (i == class -> lease_limit) {
246 log_error ("lease %s unbilled with no billing arrangement.",
247 piaddr (lease -> ip_addr));
248 return 0;
250 class_dereference (&lease -> billing_class, MDL);
251 lease_dereference (&class -> billed_leases [i], MDL);
252 class -> leases_consumed--;
253 return 1;
256 int bill_class (lease, class)
257 struct lease *lease;
258 struct class *class;
260 int i;
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)
268 return 0;
270 for (i = 0; i < class -> lease_limit; i++)
271 if (!class -> billed_leases [i])
272 break;
274 if (i == class -> lease_limit) {
275 log_error ("class billing consumption disagrees with leases.");
276 return 0;
279 lease_reference (&class -> billed_leases [i], lease, MDL);
280 class_reference (&lease -> billing_class, class, MDL);
281 class -> leases_consumed++;
282 return 1;