Annotation of embedaddon/dhcp/server/class.c, revision 1.1.1.1

1.1       misho       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>