Annotation of src/external/mpl/dhcp/dist/server/class.c, Revision 1.3
1.2 christos 1: /* $NetBSD: class.c,v 1.1.1.5 2018/04/07 20:44:27 christos Exp $ */
1.1 christos 2:
3: /* class.c
4:
5: Handling for client classes. */
6:
7: /*
8: * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
9: * Copyright (c) 1998-2003 by Internet Software Consortium
10: *
11: * This Source Code Form is subject to the terms of the Mozilla Public
12: * License, v. 2.0. If a copy of the MPL was not distributed with this
13: * file, You can obtain one at http://mozilla.org/MPL/2.0/.
14: *
15: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
18: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21: * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22: *
23: * Internet Systems Consortium, Inc.
24: * 950 Charter Street
25: * Redwood City, CA 94063
26: * <info@isc.org>
27: * https://www.isc.org/
28: *
29: */
30:
31: #include <sys/cdefs.h>
1.2 christos 32: __RCSID("$NetBSD: class.c,v 1.1.1.5 2018/04/07 20:44:27 christos Exp $");
1.1 christos 33:
34: #include "dhcpd.h"
35:
36: struct executable_statement *default_classification_rules;
37:
38: int have_billing_classes;
39:
40: /* Build the default classification rule tree. */
41:
42: void classification_setup ()
43: {
44: /* eval ... */
45: default_classification_rules = (struct executable_statement *)0;
46: if (!executable_statement_allocate (&default_classification_rules,
47: MDL))
48: log_fatal ("Can't allocate check of default collection");
49: default_classification_rules -> op = eval_statement;
50:
51: /* check-collection "default" */
52: if (!expression_allocate (&default_classification_rules -> data.eval,
53: MDL))
54: log_fatal ("Can't allocate default check expression");
55: default_classification_rules -> data.eval -> op = expr_check;
56: default_classification_rules -> data.eval -> data.check =
57: &default_collection;
58: }
59:
60: void classify_client (packet)
61: struct packet *packet;
62: {
63: execute_statements (NULL, packet, NULL, NULL, packet->options, NULL,
64: &global_scope, default_classification_rules, NULL);
65: }
66:
67: int check_collection (packet, lease, collection)
68: struct packet *packet;
69: struct lease *lease;
70: struct collection *collection;
71: {
72: struct class *class, *nc;
73: struct data_string data;
74: int matched = 0;
75: int status;
76: int ignorep;
77: int classfound;
78:
79: for (class = collection -> classes; class; class = class -> nic) {
80: #if defined (DEBUG_CLASS_MATCHING)
81: log_info ("checking against class %s...", class -> name);
82: #endif
83: memset (&data, 0, sizeof data);
84:
85: /* If there is a "match if" expression, check it. If
86: we get a match, and there's no subclass expression,
87: it's a match. If we get a match and there is a subclass
88: expression, then we check the submatch. If it's not a
89: match, that's final - we don't check the submatch. */
90:
91: if (class -> expr) {
92: status = (evaluate_boolean_expression_result
93: (&ignorep, packet, lease,
94: (struct client_state *)0,
95: packet -> options, (struct option_state *)0,
96: lease ? &lease -> scope : &global_scope,
97: class -> expr));
98: if (status) {
99: if (!class -> submatch) {
100: matched = 1;
101: #if defined (DEBUG_CLASS_MATCHING)
102: log_info ("matches class.");
103: #endif
104: classify (packet, class);
105: continue;
106: }
107: } else
108: continue;
109: }
110:
111: /* Check to see if the client matches an existing subclass.
112: If it doesn't, and this is a spawning class, spawn a new
113: subclass and put the client in it. */
114: if (class -> submatch) {
115: status = (evaluate_data_expression
116: (&data, packet, lease,
117: (struct client_state *)0,
118: packet -> options, (struct option_state *)0,
119: lease ? &lease -> scope : &global_scope,
120: class -> submatch, MDL));
121: if (status && data.len) {
122: nc = (struct class *)0;
123: classfound = class_hash_lookup (&nc, class -> hash,
124: (const char *)data.data, data.len, MDL);
125:
126: #ifdef LDAP_CONFIGURATION
127: if (!classfound && find_subclass_in_ldap (class, &nc, &data))
128: classfound = 1;
129: #endif
130:
131: if (classfound) {
132: #if defined (DEBUG_CLASS_MATCHING)
133: log_info ("matches subclass %s.",
134: print_hex_1 (data.len,
135: data.data, 60));
136: #endif
137: data_string_forget (&data, MDL);
138: classify (packet, nc);
139: matched = 1;
140: class_dereference (&nc, MDL);
141: continue;
142: }
143: if (!class -> spawning) {
144: data_string_forget (&data, MDL);
145: continue;
146: }
147: /* XXX Write out the spawned class? */
148: #if defined (DEBUG_CLASS_MATCHING)
149: log_info ("spawning subclass %s.",
150: print_hex_1 (data.len, data.data, 60));
151: #endif
152: status = class_allocate (&nc, MDL);
153: group_reference (&nc -> group,
154: class -> group, MDL);
155: class_reference (&nc -> superclass,
156: class, MDL);
157: nc -> lease_limit = class -> lease_limit;
158: nc -> dirty = 1;
159: if (nc -> lease_limit) {
160: nc -> billed_leases =
161: (dmalloc
162: (nc -> lease_limit *
163: sizeof (struct lease *),
164: MDL));
165: if (!nc -> billed_leases) {
166: log_error ("no memory for%s",
167: " billing");
168: data_string_forget
169: (&nc -> hash_string,
170: MDL);
171: class_dereference (&nc, MDL);
172: data_string_forget (&data,
173: MDL);
174: continue;
175: }
176: memset (nc -> billed_leases, 0,
177: (nc -> lease_limit *
178: sizeof (struct lease *)));
179: }
180: data_string_copy (&nc -> hash_string, &data,
181: MDL);
182: if (!class -> hash)
183: class_new_hash(&class->hash,
184: SCLASS_HASH_SIZE, MDL);
185: class_hash_add (class -> hash,
186: (const char *)
187: nc -> hash_string.data,
188: nc -> hash_string.len,
189: nc, MDL);
190: classify (packet, nc);
191: class_dereference (&nc, MDL);
192: }
1.3 ! christos 193:
! 194: data_string_forget (&data, MDL);
1.1 christos 195: }
196: }
197: return matched;
198: }
199:
200: void classify (packet, class)
201: struct packet *packet;
202: struct class *class;
203: {
204: if (packet -> class_count < PACKET_MAX_CLASSES)
205: class_reference (&packet -> classes [packet -> class_count++],
206: class, MDL);
207: else
208: log_error ("too many classes match %s",
209: print_hw_addr (packet -> raw -> htype,
210: packet -> raw -> hlen,
211: packet -> raw -> chaddr));
212: }
213:
214:
215: isc_result_t unlink_class(struct class **class) {
216: struct collection *lp;
217: struct class *cp, *pp;
218:
219: for (lp = collections; lp; lp = lp -> next) {
220: for (pp = 0, cp = lp -> classes; cp; pp = cp, cp = cp -> nic)
221: if (cp == *class) {
222: if (pp == 0) {
223: lp->classes = cp->nic;
224: } else {
225: pp->nic = cp->nic;
226: }
227: cp->nic = 0;
228: class_dereference(class, MDL);
229:
230: return ISC_R_SUCCESS;
231: }
232: }
233: return ISC_R_NOTFOUND;
234: }
235:
236:
237: isc_result_t find_class (struct class **class, const char *name,
238: const char *file, int line)
239: {
240: struct collection *lp;
241: struct class *cp;
242:
243: for (lp = collections; lp; lp = lp -> next) {
244: for (cp = lp -> classes; cp; cp = cp -> nic)
245: if (cp -> name && !strcmp (name, cp -> name)) {
246: return class_reference (class, cp, file, line);
247: }
248: }
249: return ISC_R_NOTFOUND;
250: }
251:
252: /* Removes the billing class from a lease
253: *
254: * Note that because classes can be created and removed dynamically, it is
255: * possible that the class to which a lease was billed has since been deleted.
256: * To cover the case where the lease is the last reference to a deleted class
257: * we remove the lease reference from the class first, then the class from the
258: * lease. To protect ourselves from the reverse situation, where the class is
259: * the last reference to the lease (unlikely), we create a guard reference to
260: * the lease, then remove it at the end.
261: */
262: void unbill_class (lease)
263: struct lease *lease;
264: {
265: int i;
266: struct class* class = lease->billing_class;
267: struct lease* refholder = NULL;
268:
269: /* if there's no billing to remove, nothing to do */
270: if (class == NULL) {
271: return;
272: }
273:
274: /* Find the lease in the list of the class's billed leases */
275: for (i = 0; i < class->lease_limit; i++) {
276: if (class->billed_leases[i] == lease)
277: break;
278: }
279:
280: /* Create guard reference, so class cannot be last reference to lease */
281: lease_reference(&refholder, lease, MDL);
282:
283: /* If the class doesn't have the lease, then something is broken
284: * programmatically. We'll log it but skip the lease dereference. */
285: if (i == class->lease_limit) {
286: log_error ("lease %s unbilled with no billing arrangement.",
287: piaddr(lease->ip_addr));
288: } else {
289: /* Remove the lease from the class */
290: lease_dereference(&class->billed_leases[i], MDL);
291: class->leases_consumed--;
292: }
293:
294: /* Remove the class from the lease */
295: class_dereference(&lease->billing_class, MDL);
296:
297: /* Ditch our guard reference */
298: lease_dereference(&refholder, MDL);
299: }
300:
301: int bill_class (lease, class)
302: struct lease *lease;
303: struct class *class;
304: {
305: int i;
306:
307: if (lease -> billing_class) {
308: log_error ("lease billed with existing billing arrangement.");
309: unbill_class (lease);
310: }
311:
312: if (class -> leases_consumed == class -> lease_limit)
313: return 0;
314:
315: for (i = 0; i < class -> lease_limit; i++)
316: if (!class -> billed_leases [i])
317: break;
318:
319: if (i == class -> lease_limit) {
320: log_error ("class billing consumption disagrees with leases.");
321: return 0;
322: }
323:
324: lease_reference (&class -> billed_leases [i], lease, MDL);
325: class_reference (&lease -> billing_class, class, MDL);
326: class -> leases_consumed++;
327: return 1;
328: }
CVSweb <webmaster@jp.NetBSD.org>