1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 #pragma ident   "%Z%%M% %I%     %E% SMI"
  23 
  24 /*
  25  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
  26  * Use is subject to license terms.
  27  */
  28 
  29 #include <stdio.h>
  30 #include <stdlib.h>
  31 #include <unistd.h>
  32 #include <stdarg.h>
  33 #include <sys/types.h>
  34 #include <errno.h>
  35 #include <assert.h>
  36 #include <string.h>
  37 #include <sys/syslog.h>
  38 #include <sys/socket.h>
  39 #include <netinet/in.h>
  40 #include <arpa/inet.h>
  41 #include <netinet/dhcp.h>
  42 #include "hash.h"
  43 #include "dhcpd.h"
  44 #include "per_dnet.h"
  45 
  46 /*
  47  * This file contains the code which creates, manipulates, and frees encode
  48  * structures.
  49  */
  50 
  51 /*
  52  * Free an individual encode structure, including data.
  53  */
  54 void
  55 free_encode(ENCODE *ecp)
  56 {
  57         if (ecp != NULL) {
  58                 if (ecp->data)
  59                         free(ecp->data);
  60                 free(ecp);
  61         }
  62 }
  63 
  64 /*
  65  * Dump an entire encode list, including data.
  66  */
  67 void
  68 free_encode_list(ENCODE *ecp)
  69 {
  70         ENCODE *tmp;
  71 
  72         while (ecp != NULL) {
  73                 tmp = ecp;
  74                 ecp = ecp->next;
  75                 free_encode(tmp);
  76         }
  77 }
  78 
  79 /*
  80  * Allocate an ENCODE structure, and fill it in with the passed data.
  81  *
  82  * Doesn't copy data if copy_flag is not set.
  83  *
  84  * Returns: ptr for success. Doesn't return if a failure occurs.
  85  */
  86 ENCODE *
  87 make_encode(uchar_t cat, ushort_t code, uchar_t len, void *data,
  88     int copy_flag)
  89 {
  90         ENCODE *ecp;
  91 
  92         ecp = (ENCODE *)smalloc(sizeof (ENCODE));
  93 
  94         ecp->category = cat;
  95         ecp->code = code;
  96         ecp->len = len;
  97 
  98         if (data != NULL && len != 0) {
  99                 if (copy_flag == ENC_COPY) {
 100                         ecp->data = (uchar_t *)smalloc(len);
 101                         (void) memcpy(ecp->data, data, len);
 102                 } else
 103                         ecp->data = data;
 104         }
 105         return (ecp);
 106 }
 107 
 108 /*
 109  * Find a specific code in the ENCODE list. Doesn't consider class.
 110  *
 111  * Returns: ptr if successful, NULL otherwise.
 112  */
 113 ENCODE *
 114 find_encode(ENCODE *eclp, uchar_t cat, ushort_t code)
 115 {
 116         for (; eclp != NULL; eclp = eclp->next) {
 117                 if (eclp->category == cat && eclp->code == code)
 118                         return (eclp);
 119         }
 120         return (NULL);
 121 }
 122 
 123 /*
 124  * Duplicate the passed encode structure.
 125  */
 126 ENCODE *
 127 dup_encode(ENCODE *ecp)
 128 {
 129         assert(ecp != NULL);
 130         return (make_encode(ecp->category, ecp->code, ecp->len, ecp->data,
 131             ENC_COPY));
 132 }
 133 
 134 /*
 135  * Duplicate an encode list. May be called with NULL as a convenience.
 136  */
 137 ENCODE *
 138 dup_encode_list(ENCODE *ecp)
 139 {
 140         ENCODE *pp, *np, *headp;
 141 
 142         if (ecp == NULL)
 143                 return (NULL);
 144 
 145         /*
 146          * Note: pp/np are used as placeholders in parallel list.
 147          */
 148         pp = headp = NULL;
 149         for (; ecp != NULL; ecp = ecp->next) {
 150                 np = dup_encode(ecp);
 151                 if (pp == NULL) {
 152                         headp = np;
 153                         np->prev = NULL;
 154                 } else {
 155                         pp->next = np;
 156                         np->prev = pp;
 157                 }
 158                 pp = np;
 159         }
 160         return (headp);
 161 }
 162 
 163 /*
 164  * Given two ENCODE lists,  produce NEW ENCODE list by "OR"ing the first
 165  * encode list with the second. Note that the settings in the second encode
 166  * list override any identical code settings in the first encode list.
 167  *
 168  * The primary list is copied if flags argument is ENC_COPY. Class is not
 169  * considered.
 170  *
 171  * Returns a ptr to the merged list for success, NULL ptr otherwise.
 172  */
 173 ENCODE *
 174 combine_encodes(ENCODE *first_ecp, ENCODE *second_ecp, int flags)
 175 {
 176         ENCODE *ep;
 177 
 178         if (first_ecp != NULL) {
 179                 if (flags == ENC_COPY)
 180                         first_ecp = dup_encode_list(first_ecp);
 181 
 182                 for (ep = second_ecp; ep != NULL; ep = ep->next)
 183                         replace_encode(&first_ecp, ep, ENC_COPY);
 184         } else {
 185                 first_ecp = dup_encode_list(second_ecp);
 186         }
 187         return (first_ecp);
 188 }
 189 
 190 /*
 191  * Replace/add the encode matching the code value of the second ENCODE
 192  * parameter in the list represented by the first ENCODE parameter.
 193  */
 194 void
 195 replace_encode(ENCODE **elistpp, ENCODE *rp, int flags)
 196 {
 197         ENCODE *wp;
 198 
 199         assert(elistpp != NULL && rp != NULL);
 200 
 201         if (flags == ENC_COPY)
 202                 rp = dup_encode(rp);
 203 
 204         if (*elistpp == NULL) {
 205                 *elistpp = rp;
 206                 return;
 207         }
 208         wp = find_encode(*elistpp, rp->category, rp->code);
 209 
 210         if (wp == NULL) {
 211                 rp->next = *elistpp;
 212                 rp->next->prev = rp;
 213                 *elistpp = rp;
 214                 rp->prev = NULL;
 215         } else {
 216                 if (wp->prev == NULL) {
 217                         rp->next = wp->next;
 218                         *elistpp = rp;
 219                         rp->prev = NULL;
 220                 } else {
 221                         rp->next = wp->next;
 222                         rp->prev = wp->prev;
 223                         wp->prev->next = rp;
 224                 }
 225                 if (wp->next != NULL)
 226                         wp->next->prev = rp;
 227                 free_encode(wp);
 228         }
 229 }
 230 
 231 /*
 232  * Given a MACRO and a class name, return the ENCODE list for
 233  * that class name, or null if a ENCODE list by that class doesn't exist.
 234  */
 235 ENCODE *
 236 vendor_encodes(MACRO *mp, char *class)
 237 {
 238         VNDLIST **tvpp;
 239         int     i;
 240 
 241         assert(mp != NULL && class != NULL);
 242 
 243         for (tvpp = mp->list, i = 0; tvpp != NULL && i < mp->classes; i++) {
 244                 if (strcmp(tvpp[i]->class, class) == 0)
 245                         return (tvpp[i]->head);
 246         }
 247         return (NULL);
 248 }