File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / server / class.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:06:54 2012 UTC (11 years, 8 months ago) by misho
Branches: dhcp, MAIN
CVS tags: v4_1_R7p0, v4_1_R7, v4_1_R4, HEAD
dhcp 4.1 r7

    1: /* class.c
    2: 
    3:    Handling for client classes. */
    4: 
    5: /*
    6:  * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC")
    7:  * Copyright (c) 1998-2003 by Internet Software Consortium
    8:  *
    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.
   12:  *
   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.
   20:  *
   21:  *   Internet Systems Consortium, Inc.
   22:  *   950 Charter Street
   23:  *   Redwood City, CA 94063
   24:  *   <info@isc.org>
   25:  *   https://www.isc.org/
   26:  *
   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:  * ``https://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''.
   33:  */
   34: 
   35: #include "dhcpd.h"
   36: 
   37: struct collection default_collection = {
   38: 	(struct collection *)0,
   39: 	"default",
   40: 	(struct class *)0,
   41: };
   42: 
   43: struct collection *collections = &default_collection;
   44: struct executable_statement *default_classification_rules;
   45: 
   46: int have_billing_classes;
   47: 
   48: /* Build the default classification rule tree. */
   49: 
   50: void classification_setup ()
   51: {
   52: 	/* eval ... */
   53: 	default_classification_rules = (struct executable_statement *)0;
   54: 	if (!executable_statement_allocate (&default_classification_rules,
   55: 					    MDL))
   56: 		log_fatal ("Can't allocate check of default collection");
   57: 	default_classification_rules -> op = eval_statement;
   58: 
   59: 	/* check-collection "default" */
   60: 	if (!expression_allocate (&default_classification_rules -> data.eval,
   61: 				  MDL))
   62: 		log_fatal ("Can't allocate default check expression");
   63: 	default_classification_rules -> data.eval -> op = expr_check;
   64: 	default_classification_rules -> data.eval -> data.check =
   65: 		&default_collection;
   66: }
   67: 
   68: void classify_client (packet)
   69: 	struct packet *packet;
   70: {
   71: 	execute_statements ((struct binding_value **)0, packet,
   72: 			    (struct lease *)0, (struct client_state *)0,
   73: 			    packet -> options, (struct option_state *)0,
   74: 			    &global_scope, default_classification_rules);
   75: }
   76: 
   77: int check_collection (packet, lease, collection)
   78: 	struct packet *packet;
   79: 	struct lease *lease;
   80: 	struct collection *collection;
   81: {
   82: 	struct class *class, *nc;
   83: 	struct data_string data;
   84: 	int matched = 0;
   85: 	int status;
   86: 	int ignorep;
   87: 
   88: 	for (class = collection -> classes; class; class = class -> nic) {
   89: #if defined (DEBUG_CLASS_MATCHING)
   90: 		log_info ("checking against class %s...", class -> name);
   91: #endif
   92: 		memset (&data, 0, sizeof data);
   93: 
   94: 		/* If there is a "match if" expression, check it.   If
   95: 		   we get a match, and there's no subclass expression,
   96: 		   it's a match.   If we get a match and there is a subclass
   97: 		   expression, then we check the submatch.   If it's not a
   98: 		   match, that's final - we don't check the submatch. */
   99: 
  100: 		if (class -> expr) {
  101: 			status = (evaluate_boolean_expression_result
  102: 				  (&ignorep, packet, lease,
  103: 				   (struct client_state *)0,
  104: 				   packet -> options, (struct option_state *)0,
  105: 				   lease ? &lease -> scope : &global_scope,
  106: 				   class -> expr));
  107: 			if (status) {
  108: 				if (!class -> submatch) {
  109: 					matched = 1;
  110: #if defined (DEBUG_CLASS_MATCHING)
  111: 					log_info ("matches class.");
  112: #endif
  113: 					classify (packet, class);
  114: 					continue;
  115: 				}
  116: 			} else
  117: 				continue;
  118: 		}
  119: 
  120: 		/* Check to see if the client matches an existing subclass.
  121: 		   If it doesn't, and this is a spawning class, spawn a new
  122: 		   subclass and put the client in it. */
  123: 		if (class -> submatch) {
  124: 			status = (evaluate_data_expression
  125: 				  (&data, packet, lease,
  126: 				   (struct client_state *)0,
  127: 				   packet -> options, (struct option_state *)0,
  128: 				   lease ? &lease -> scope : &global_scope,
  129: 				   class -> submatch, MDL));
  130: 			if (status && data.len) {
  131: 				nc = (struct class *)0;
  132: 				if (class_hash_lookup (&nc, class -> hash,
  133: 						       (const char *)data.data,
  134: 						       data.len, MDL)) {
  135: #if defined (DEBUG_CLASS_MATCHING)
  136: 					log_info ("matches subclass %s.",
  137: 					      print_hex_1 (data.len,
  138: 							   data.data, 60));
  139: #endif
  140: 					data_string_forget (&data, MDL);
  141: 					classify (packet, nc);
  142: 					matched = 1;
  143: 					class_dereference (&nc, MDL);
  144: 					continue;
  145: 				}
  146: 				if (!class -> spawning) {
  147: 					data_string_forget (&data, MDL);
  148: 					continue;
  149: 				}
  150: 				/* XXX Write out the spawned class? */
  151: #if defined (DEBUG_CLASS_MATCHING)
  152: 				log_info ("spawning subclass %s.",
  153: 				      print_hex_1 (data.len, data.data, 60));
  154: #endif
  155: 				status = class_allocate (&nc, MDL);
  156: 				group_reference (&nc -> group,
  157: 						 class -> group, MDL);
  158: 				class_reference (&nc -> superclass,
  159: 						 class, MDL);
  160: 				nc -> lease_limit = class -> lease_limit;
  161: 				nc -> dirty = 1;
  162: 				if (nc -> lease_limit) {
  163: 					nc -> billed_leases =
  164: 						(dmalloc
  165: 						 (nc -> lease_limit *
  166: 						  sizeof (struct lease *),
  167: 						  MDL));
  168: 					if (!nc -> billed_leases) {
  169: 						log_error ("no memory for%s",
  170: 							   " billing");
  171: 						data_string_forget
  172: 							(&nc -> hash_string,
  173: 							 MDL);
  174: 						class_dereference (&nc, MDL);
  175: 						data_string_forget (&data,
  176: 								    MDL);
  177: 						continue;
  178: 					}
  179: 					memset (nc -> billed_leases, 0,
  180: 						(nc -> lease_limit *
  181: 						 sizeof nc -> billed_leases));
  182: 				}
  183: 				data_string_copy (&nc -> hash_string, &data,
  184: 						  MDL);
  185: 				data_string_forget (&data, MDL);
  186: 				if (!class -> hash)
  187: 				    class_new_hash(&class->hash,
  188: 						   SCLASS_HASH_SIZE, MDL);
  189: 				class_hash_add (class -> hash,
  190: 						(const char *)
  191: 						nc -> hash_string.data,
  192: 						nc -> hash_string.len,
  193: 						nc, MDL);
  194: 				classify (packet, nc);
  195: 				class_dereference (&nc, MDL);
  196: 			}
  197: 		}
  198: 	}
  199: 	return matched;
  200: }
  201: 
  202: void classify (packet, class)
  203: 	struct packet *packet;
  204: 	struct class *class;
  205: {
  206: 	if (packet -> class_count < PACKET_MAX_CLASSES)
  207: 		class_reference (&packet -> classes [packet -> class_count++],
  208: 				 class, MDL);
  209: 	else
  210: 		log_error ("too many classes match %s",
  211: 		      print_hw_addr (packet -> raw -> htype,
  212: 				     packet -> raw -> hlen,
  213: 				     packet -> raw -> chaddr));
  214: }
  215: 
  216: 
  217: isc_result_t unlink_class(struct class **class) {
  218: 	struct collection *lp;
  219: 	struct class *cp, *pp;
  220: 
  221: 	for (lp = collections; lp; lp = lp -> next) {
  222: 		for (pp = 0, cp = lp -> classes; cp; pp = cp, cp = cp -> nic)
  223: 			if (cp == *class) {
  224: 				if (pp == 0) {
  225: 					lp->classes = cp->nic;
  226: 				} else {
  227: 					pp->nic = cp->nic;
  228: 				}
  229: 				cp->nic = 0;
  230: 				class_dereference(class, MDL);
  231: 
  232: 				return ISC_R_SUCCESS;
  233: 			}
  234: 	}
  235: 	return ISC_R_NOTFOUND;
  236: }
  237: 
  238: 	
  239: isc_result_t find_class (struct class **class, const char *name,
  240: 			 const char *file, int line)
  241: {
  242: 	struct collection *lp;
  243: 	struct class *cp;
  244: 
  245: 	for (lp = collections; lp; lp = lp -> next) {
  246: 		for (cp = lp -> classes; cp; cp = cp -> nic)
  247: 			if (cp -> name && !strcmp (name, cp -> name)) {
  248: 				return class_reference (class, cp, file, line);
  249: 			}
  250: 	}
  251: 	return ISC_R_NOTFOUND;
  252: }
  253: 
  254: int unbill_class (lease, class)
  255: 	struct lease *lease;
  256: 	struct class *class;
  257: {
  258: 	int i;
  259: 
  260: 	for (i = 0; i < class -> lease_limit; i++)
  261: 		if (class -> billed_leases [i] == lease)
  262: 			break;
  263: 	if (i == class -> lease_limit) {
  264: 		log_error ("lease %s unbilled with no billing arrangement.",
  265: 		      piaddr (lease -> ip_addr));
  266: 		return 0;
  267: 	}
  268: 	class_dereference (&lease -> billing_class, MDL);
  269: 	lease_dereference (&class -> billed_leases [i], MDL);
  270: 	class -> leases_consumed--;
  271: 	return 1;
  272: }
  273: 
  274: int bill_class (lease, class)
  275: 	struct lease *lease;
  276: 	struct class *class;
  277: {
  278: 	int i;
  279: 
  280: 	if (lease -> billing_class) {
  281: 		log_error ("lease billed with existing billing arrangement.");
  282: 		unbill_class (lease, lease -> billing_class);
  283: 	}
  284: 
  285: 	if (class -> leases_consumed == class -> lease_limit)
  286: 		return 0;
  287: 
  288: 	for (i = 0; i < class -> lease_limit; i++)
  289: 		if (!class -> billed_leases [i])
  290: 			break;
  291: 
  292: 	if (i == class -> lease_limit) {
  293: 		log_error ("class billing consumption disagrees with leases.");
  294: 		return 0;
  295: 	}
  296: 
  297: 	lease_reference (&class -> billed_leases [i], lease, MDL);
  298: 	class_reference (&lease -> billing_class, class, MDL);
  299: 	class -> leases_consumed++;
  300: 	return 1;
  301: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>