00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "dhcpd.h"
00031
00032 struct collection default_collection = {
00033 (struct collection *)0,
00034 "default",
00035 (struct class *)0,
00036 };
00037
00038 struct collection *collections = &default_collection;
00039 struct executable_statement *default_classification_rules;
00040
00041 int have_billing_classes;
00042
00043
00044
00045 void classification_setup ()
00046 {
00047
00048 default_classification_rules = (struct executable_statement *)0;
00049 if (!executable_statement_allocate (&default_classification_rules,
00050 MDL))
00051 log_fatal ("Can't allocate check of default collection");
00052 default_classification_rules -> op = eval_statement;
00053
00054
00055 if (!expression_allocate (&default_classification_rules -> data.eval,
00056 MDL))
00057 log_fatal ("Can't allocate default check expression");
00058 default_classification_rules -> data.eval -> op = expr_check;
00059 default_classification_rules -> data.eval -> data.check =
00060 &default_collection;
00061 }
00062
00063 void classify_client (packet)
00064 struct packet *packet;
00065 {
00066 execute_statements (NULL, packet, NULL, NULL, packet->options, NULL,
00067 &global_scope, default_classification_rules, NULL);
00068 }
00069
00070 int check_collection (packet, lease, collection)
00071 struct packet *packet;
00072 struct lease *lease;
00073 struct collection *collection;
00074 {
00075 struct class *class, *nc;
00076 struct data_string data;
00077 int matched = 0;
00078 int status;
00079 int ignorep;
00080 int classfound;
00081
00082 for (class = collection -> classes; class; class = class -> nic) {
00083 #if defined (DEBUG_CLASS_MATCHING)
00084 log_info ("checking against class %s...", class -> name);
00085 #endif
00086 memset (&data, 0, sizeof data);
00087
00088
00089
00090
00091
00092
00093
00094 if (class -> expr) {
00095 status = (evaluate_boolean_expression_result
00096 (&ignorep, packet, lease,
00097 (struct client_state *)0,
00098 packet -> options, (struct option_state *)0,
00099 lease ? &lease -> scope : &global_scope,
00100 class -> expr));
00101 if (status) {
00102 if (!class -> submatch) {
00103 matched = 1;
00104 #if defined (DEBUG_CLASS_MATCHING)
00105 log_info ("matches class.");
00106 #endif
00107 classify (packet, class);
00108 continue;
00109 }
00110 } else
00111 continue;
00112 }
00113
00114
00115
00116
00117 if (class -> submatch) {
00118 status = (evaluate_data_expression
00119 (&data, packet, lease,
00120 (struct client_state *)0,
00121 packet -> options, (struct option_state *)0,
00122 lease ? &lease -> scope : &global_scope,
00123 class -> submatch, MDL));
00124 if (status && data.len) {
00125 nc = (struct class *)0;
00126 classfound = class_hash_lookup (&nc, class -> hash,
00127 (const char *)data.data, data.len, MDL);
00128
00129 #ifdef LDAP_CONFIGURATION
00130 if (!classfound && find_subclass_in_ldap (class, &nc, &data))
00131 classfound = 1;
00132 #endif
00133
00134 if (classfound) {
00135 #if defined (DEBUG_CLASS_MATCHING)
00136 log_info ("matches subclass %s.",
00137 print_hex_1 (data.len,
00138 data.data, 60));
00139 #endif
00140 data_string_forget (&data, MDL);
00141 classify (packet, nc);
00142 matched = 1;
00143 class_dereference (&nc, MDL);
00144 continue;
00145 }
00146 if (!class -> spawning) {
00147 data_string_forget (&data, MDL);
00148 continue;
00149 }
00150
00151 #if defined (DEBUG_CLASS_MATCHING)
00152 log_info ("spawning subclass %s.",
00153 print_hex_1 (data.len, data.data, 60));
00154 #endif
00155 status = class_allocate (&nc, MDL);
00156 group_reference (&nc -> group,
00157 class -> group, MDL);
00158 class_reference (&nc -> superclass,
00159 class, MDL);
00160 nc -> lease_limit = class -> lease_limit;
00161 nc -> dirty = 1;
00162 if (nc -> lease_limit) {
00163 nc -> billed_leases =
00164 (dmalloc
00165 (nc -> lease_limit *
00166 sizeof (struct lease *),
00167 MDL));
00168 if (!nc -> billed_leases) {
00169 log_error ("no memory for%s",
00170 " billing");
00171 data_string_forget
00172 (&nc -> hash_string,
00173 MDL);
00174 class_dereference (&nc, MDL);
00175 data_string_forget (&data,
00176 MDL);
00177 continue;
00178 }
00179 memset (nc -> billed_leases, 0,
00180 (nc -> lease_limit *
00181 sizeof (struct lease *)));
00182 }
00183 data_string_copy (&nc -> hash_string, &data,
00184 MDL);
00185 data_string_forget (&data, MDL);
00186 if (!class -> hash)
00187 class_new_hash(&class->hash,
00188 SCLASS_HASH_SIZE, MDL);
00189 class_hash_add (class -> hash,
00190 (const char *)
00191 nc -> hash_string.data,
00192 nc -> hash_string.len,
00193 nc, MDL);
00194 classify (packet, nc);
00195 class_dereference (&nc, MDL);
00196 }
00197 }
00198 }
00199 return matched;
00200 }
00201
00202 void classify (packet, class)
00203 struct packet *packet;
00204 struct class *class;
00205 {
00206 if (packet -> class_count < PACKET_MAX_CLASSES)
00207 class_reference (&packet -> classes [packet -> class_count++],
00208 class, MDL);
00209 else
00210 log_error ("too many classes match %s",
00211 print_hw_addr (packet -> raw -> htype,
00212 packet -> raw -> hlen,
00213 packet -> raw -> chaddr));
00214 }
00215
00216
00217 isc_result_t unlink_class(struct class **class) {
00218 struct collection *lp;
00219 struct class *cp, *pp;
00220
00221 for (lp = collections; lp; lp = lp -> next) {
00222 for (pp = 0, cp = lp -> classes; cp; pp = cp, cp = cp -> nic)
00223 if (cp == *class) {
00224 if (pp == 0) {
00225 lp->classes = cp->nic;
00226 } else {
00227 pp->nic = cp->nic;
00228 }
00229 cp->nic = 0;
00230 class_dereference(class, MDL);
00231
00232 return ISC_R_SUCCESS;
00233 }
00234 }
00235 return ISC_R_NOTFOUND;
00236 }
00237
00238
00239 isc_result_t find_class (struct class **class, const char *name,
00240 const char *file, int line)
00241 {
00242 struct collection *lp;
00243 struct class *cp;
00244
00245 for (lp = collections; lp; lp = lp -> next) {
00246 for (cp = lp -> classes; cp; cp = cp -> nic)
00247 if (cp -> name && !strcmp (name, cp -> name)) {
00248 return class_reference (class, cp, file, line);
00249 }
00250 }
00251 return ISC_R_NOTFOUND;
00252 }
00253
00254 int unbill_class (lease, class)
00255 struct lease *lease;
00256 struct class *class;
00257 {
00258 int i;
00259
00260 for (i = 0; i < class -> lease_limit; i++)
00261 if (class -> billed_leases [i] == lease)
00262 break;
00263 if (i == class -> lease_limit) {
00264 log_error ("lease %s unbilled with no billing arrangement.",
00265 piaddr (lease -> ip_addr));
00266 return 0;
00267 }
00268 class_dereference (&lease -> billing_class, MDL);
00269 lease_dereference (&class -> billed_leases [i], MDL);
00270 class -> leases_consumed--;
00271 return 1;
00272 }
00273
00274 int bill_class (lease, class)
00275 struct lease *lease;
00276 struct class *class;
00277 {
00278 int i;
00279
00280 if (lease -> billing_class) {
00281 log_error ("lease billed with existing billing arrangement.");
00282 unbill_class (lease, lease -> billing_class);
00283 }
00284
00285 if (class -> leases_consumed == class -> lease_limit)
00286 return 0;
00287
00288 for (i = 0; i < class -> lease_limit; i++)
00289 if (!class -> billed_leases [i])
00290 break;
00291
00292 if (i == class -> lease_limit) {
00293 log_error ("class billing consumption disagrees with leases.");
00294 return 0;
00295 }
00296
00297 lease_reference (&class -> billed_leases [i], lease, MDL);
00298 class_reference (&lease -> billing_class, class, MDL);
00299 class -> leases_consumed++;
00300 return 1;
00301 }