patch tsoome-feedback

   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 (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2012 Milan Jurik. All rights reserved.
  25  */
  26 
  27 #include <assert.h>
  28 #include <stdio.h>
  29 #include <stdlib.h>
  30 #include <string.h>
  31 #include <sys/types.h>
  32 #include <libdlwlan.h>
  33 #include <libnvpair.h>
  34 
  35 #include "libnwam_impl.h"
  36 #include <libnwam_priv.h>
  37 #include <libnwam.h>
  38 
  39 /*
  40  * Internal implementation of libnwam in-memory objects and values.  Objects
  41  * are nvlists.
  42  */
  43 
  44 void
  45 nwam_value_free(nwam_value_t value)
  46 {
  47         uint_t i;
  48 
  49         if (value == NULL)
  50                 return;
  51 
  52         switch (value->nwv_value_type) {
  53         case NWAM_VALUE_TYPE_BOOLEAN:
  54                 free(value->nwv_values.nwv_boolean);
  55                 break;
  56         case NWAM_VALUE_TYPE_INT64:
  57                 free(value->nwv_values.nwv_int64);
  58                 break;
  59         case NWAM_VALUE_TYPE_UINT64:
  60                 free(value->nwv_values.nwv_uint64);
  61                 break;
  62         case NWAM_VALUE_TYPE_STRING:
  63                 for (i = 0; i < value->nwv_value_numvalues; i++)
  64                         free(value->nwv_values.nwv_string[i]);
  65                 free(value->nwv_values.nwv_string);
  66                 break;
  67         }
  68         free(value);
  69 }
  70 
  71 nwam_error_t
  72 nwam_value_create(nwam_value_type_t value_type, void *values, uint_t numvalues,
  73     nwam_value_t *valuep)
  74 {
  75         nwam_value_t newvalue;
  76         boolean_t *values_boolean;
  77         int64_t *values_int64;
  78         uint64_t *values_uint64;
  79         char **values_string;
  80         int i, j;
  81         nwam_error_t err = NWAM_SUCCESS;
  82 
  83         *valuep = NULL;
  84 
  85         if ((newvalue = calloc(1, sizeof (struct nwam_value))) == NULL)
  86                 return (NWAM_NO_MEMORY);
  87 
  88         newvalue->nwv_value_type = value_type;
  89         newvalue->nwv_value_numvalues = numvalues;
  90 
  91         switch (value_type) {
  92         case NWAM_VALUE_TYPE_BOOLEAN:
  93                 values_boolean = values;
  94                 if ((newvalue->nwv_values.nwv_boolean =
  95                     calloc(numvalues, sizeof (boolean_t))) == NULL) {
  96                         free(newvalue);
  97                         return (NWAM_NO_MEMORY);
  98                 }
  99                 for (i = 0; i < numvalues; i++)
 100                         newvalue->nwv_values.nwv_boolean[i] = values_boolean[i];
 101                 break;
 102         case NWAM_VALUE_TYPE_INT64:
 103                 values_int64 = values;
 104                 if ((newvalue->nwv_values.nwv_int64 =
 105                     calloc(numvalues, sizeof (int64_t))) == NULL) {
 106                         free(newvalue);
 107                         return (NWAM_NO_MEMORY);
 108                 }
 109                 for (i = 0; i < numvalues; i++)
 110                         newvalue->nwv_values.nwv_int64[i] = values_int64[i];
 111                 break;
 112         case NWAM_VALUE_TYPE_UINT64:
 113                 values_uint64 = values;
 114                 if ((newvalue->nwv_values.nwv_uint64 =
 115                     calloc(numvalues, sizeof (uint64_t))) == NULL) {
 116                         free(newvalue);
 117                         return (NWAM_NO_MEMORY);
 118                 }
 119                 for (i = 0; i < numvalues; i++)
 120                         newvalue->nwv_values.nwv_uint64[i] = values_uint64[i];
 121                 break;
 122         case NWAM_VALUE_TYPE_STRING:
 123                 values_string = values;
 124                 if ((newvalue->nwv_values.nwv_string =
 125                     calloc(numvalues, sizeof (char *))) == NULL) {
 126                         free(newvalue);
 127                         return (NWAM_NO_MEMORY);
 128                 }
 129                 for (i = 0; i < numvalues; i++) {
 130                         if (strnlen(values_string[i], NWAM_MAX_VALUE_LEN) ==
 131                             NWAM_MAX_VALUE_LEN) {
 132                                 err = NWAM_ENTITY_INVALID_VALUE;
 133                         } else if ((newvalue->nwv_values.nwv_string[i] =
 134                             strdup(values_string[i])) == NULL) {
 135                                 err = NWAM_NO_MEMORY;
 136                         }
 137                         if (err != NWAM_SUCCESS) {
 138                                 for (j = 0; j < i; j++)
 139                                         free(
 140                                             newvalue->nwv_values.nwv_string[i]);
 141                                 free(newvalue->nwv_values.nwv_string);
 142                                 free(newvalue);
 143                                 return (err);
 144                         }
 145                 }
 146                 break;
 147         default:
 148                 break;
 149         }
 150 
 151         *valuep = newvalue;
 152         return (NWAM_SUCCESS);
 153 }
 154 
 155 nwam_error_t
 156 nwam_value_copy(nwam_value_t old, nwam_value_t *newp)
 157 {
 158         void *values;
 159 
 160         assert(old != NULL && newp != NULL);
 161 
 162         switch (old->nwv_value_type) {
 163         case NWAM_VALUE_TYPE_BOOLEAN:
 164                 values = old->nwv_values.nwv_boolean;
 165                 break;
 166         case NWAM_VALUE_TYPE_INT64:
 167                 values = old->nwv_values.nwv_int64;
 168                 break;
 169         case NWAM_VALUE_TYPE_UINT64:
 170                 values = old->nwv_values.nwv_uint64;
 171                 break;
 172         case NWAM_VALUE_TYPE_STRING:
 173                 values = old->nwv_values.nwv_string;
 174                 break;
 175         default:
 176                 return (NWAM_INVALID_ARG);
 177         }
 178         return (nwam_value_create(old->nwv_value_type, values,
 179             old->nwv_value_numvalues, newp));
 180 }
 181 nwam_error_t
 182 nwam_value_create_boolean_array(boolean_t *values, uint_t numvalues,
 183     nwam_value_t *valuep)
 184 {
 185         return (nwam_value_create(NWAM_VALUE_TYPE_BOOLEAN, values, numvalues,
 186             valuep));
 187 }
 188 
 189 nwam_error_t
 190 nwam_value_create_boolean(boolean_t value, nwam_value_t *valuep)
 191 {
 192         return (nwam_value_create_boolean_array(&value, 1, valuep));
 193 }
 194 
 195 nwam_error_t
 196 nwam_value_create_int64_array(int64_t *values, uint_t numvalues,
 197     nwam_value_t *valuep)
 198 {
 199         return (nwam_value_create(NWAM_VALUE_TYPE_INT64, values, numvalues,
 200             valuep));
 201 }
 202 
 203 nwam_error_t
 204 nwam_value_create_int64(int64_t value, nwam_value_t *valuep)
 205 {
 206         return (nwam_value_create_int64_array(&value, 1, valuep));
 207 }
 208 
 209 nwam_error_t
 210 nwam_value_create_uint64_array(uint64_t *values, uint_t numvalues,
 211     nwam_value_t *valuep)
 212 {
 213         return (nwam_value_create(NWAM_VALUE_TYPE_UINT64, values, numvalues,
 214             valuep));
 215 }
 216 
 217 nwam_error_t
 218 nwam_value_create_uint64(uint64_t value, nwam_value_t *valuep)
 219 {
 220         return (nwam_value_create_uint64_array(&value, 1, valuep));
 221 }
 222 
 223 nwam_error_t
 224 nwam_value_create_string_array(char **values, uint_t numvalues,
 225     nwam_value_t *valuep)
 226 {
 227         return (nwam_value_create(NWAM_VALUE_TYPE_STRING, values, numvalues,
 228             valuep));
 229 }
 230 
 231 nwam_error_t
 232 nwam_value_create_string(char *value, nwam_value_t *valuep)
 233 {
 234         return (nwam_value_create_string_array(&value, 1, valuep));
 235 }
 236 
 237 nwam_error_t
 238 nwam_value_get_boolean_array(nwam_value_t value, boolean_t **valuesp,
 239     uint_t *numvaluesp)
 240 {
 241         assert(value != NULL && numvaluesp != NULL && valuesp != NULL);
 242 
 243         *numvaluesp = value->nwv_value_numvalues;
 244         *valuesp = value->nwv_values.nwv_boolean;
 245         return (NWAM_SUCCESS);
 246 }
 247 
 248 nwam_error_t
 249 nwam_value_get_boolean(nwam_value_t value, boolean_t *valuep)
 250 {
 251         uint_t numvalues;
 252         boolean_t *myvaluesp;
 253         nwam_error_t err;
 254 
 255         err = nwam_value_get_boolean_array(value, &myvaluesp, &numvalues);
 256         if (err != NWAM_SUCCESS)
 257                 return (err);
 258         if (numvalues != 1)
 259                 return (NWAM_ENTITY_MULTIPLE_VALUES);
 260 
 261         *valuep = myvaluesp[0];
 262         return (NWAM_SUCCESS);
 263 }
 264 
 265 nwam_error_t
 266 nwam_value_get_int64_array(nwam_value_t value, int64_t **valuesp,
 267     uint_t *numvaluesp)
 268 {
 269         assert(value != NULL && numvaluesp != NULL && valuesp != NULL);
 270 
 271         *numvaluesp = value->nwv_value_numvalues;
 272         *valuesp = value->nwv_values.nwv_int64;
 273         return (NWAM_SUCCESS);
 274 }
 275 
 276 nwam_error_t
 277 nwam_value_get_int64(nwam_value_t value, int64_t *valuep)
 278 {
 279         uint_t numvalues;
 280         int64_t *myvaluesp;
 281         nwam_error_t err;
 282 
 283         err = nwam_value_get_int64_array(value, &myvaluesp, &numvalues);
 284         if (err != NWAM_SUCCESS)
 285                 return (err);
 286         if (numvalues != 1)
 287                 return (NWAM_ENTITY_MULTIPLE_VALUES);
 288 
 289         *valuep = myvaluesp[0];
 290         return (NWAM_SUCCESS);
 291 }
 292 
 293 nwam_error_t
 294 nwam_value_get_uint64_array(nwam_value_t value, uint64_t **valuesp,
 295     uint_t *numvaluesp)
 296 {
 297         assert(value != NULL && numvaluesp != NULL && valuesp != NULL);
 298 
 299         *numvaluesp = value->nwv_value_numvalues;
 300         *valuesp = value->nwv_values.nwv_uint64;
 301         return (NWAM_SUCCESS);
 302 }
 303 
 304 nwam_error_t
 305 nwam_value_get_uint64(nwam_value_t value, uint64_t *valuep)
 306 {
 307         uint_t numvalues;
 308         uint64_t *myvaluesp;
 309         nwam_error_t err;
 310 
 311         err = nwam_value_get_uint64_array(value, &myvaluesp, &numvalues);
 312         if (err != NWAM_SUCCESS)
 313                 return (err);
 314         if (numvalues != 1)
 315                 return (NWAM_ENTITY_MULTIPLE_VALUES);
 316 
 317         *valuep = myvaluesp[0];
 318         return (NWAM_SUCCESS);
 319 }
 320 
 321 nwam_error_t
 322 nwam_value_get_string_array(nwam_value_t value, char ***valuesp,
 323     uint_t *numvaluesp)
 324 {
 325         assert(value != NULL && numvaluesp != NULL && valuesp != NULL);
 326 
 327         *numvaluesp = value->nwv_value_numvalues;
 328         *valuesp = value->nwv_values.nwv_string;
 329         return (NWAM_SUCCESS);
 330 }
 331 
 332 nwam_error_t
 333 nwam_value_get_string(nwam_value_t value, char **valuep)
 334 {
 335         uint_t numvalues;
 336         char **myvaluesp;
 337         nwam_error_t err;
 338 
 339         err = nwam_value_get_string_array(value, &myvaluesp, &numvalues);
 340         if (err != NWAM_SUCCESS)
 341                 return (err);
 342         if (numvalues != 1)
 343                 return (NWAM_ENTITY_MULTIPLE_VALUES);
 344 
 345         *valuep = myvaluesp[0];
 346         return (NWAM_SUCCESS);
 347 }
 348 
 349 nwam_error_t
 350 nwam_value_get_type(nwam_value_t value, nwam_value_type_t *typep)
 351 {
 352         *typep = value->nwv_value_type;
 353         return (NWAM_SUCCESS);
 354 }
 355 
 356 nwam_error_t
 357 nwam_value_get_numvalues(nwam_value_t value, uint_t *numvaluesp)
 358 {
 359         *numvaluesp = value->nwv_value_numvalues;
 360         return (NWAM_SUCCESS);
 361 }
 362 
 363 /*
 364  * Generic object data functions. We hide nvlist implementation
 365  * from NCP, ENM and location implementations.
 366  */
 367 nwam_error_t
 368 nwam_alloc_object_list(void *list)
 369 {
 370         int nverr;
 371 
 372         assert(list != NULL);
 373 
 374         if ((nverr = nvlist_alloc((nvlist_t **)list, NV_UNIQUE_NAME, 0)) != 0)
 375                 return (nwam_errno_to_nwam_error(nverr));
 376 
 377         return (NWAM_SUCCESS);
 378 }
 379 
 380 void
 381 nwam_free_object_list(void *list)
 382 {
 383         if (list != NULL)
 384                 nvlist_free(list);
 385 }
 386 
 387 nwam_error_t
 388 nwam_dup_object_list(void *oldlist, void *newlist)
 389 {
 390         int nverr;
 391 
 392         assert(oldlist != NULL && newlist != NULL);
 393 
 394         if ((nverr = nvlist_dup(oldlist, newlist, 0)) != 0)
 395                 return (nwam_errno_to_nwam_error(nverr));
 396 
 397         return (NWAM_SUCCESS);
 398 }
 399 
 400 /* Add child object list to parent object list using property name childname */
 401 nwam_error_t
 402 nwam_object_list_add_object_list(void *parentlist, char *childname,
 403     void *childlist)
 404 {
 405         return (nwam_errno_to_nwam_error(nvlist_add_nvlist(parentlist,
 406             childname, childlist)));
 407 }
 408 
 409 /* Remove object list from parent object list */
 410 nwam_error_t
 411 nwam_object_list_remove_object_list(void *parentlist, char *childname)
 412 {
 413         return (nwam_errno_to_nwam_error(nvlist_remove_all(parentlist,
 414             childname)));
 415 }
 416 
 417 /*
 418  * Get next object list (nvlist) after lastname.  Used to walk NCUs, ENMs and
 419  * locations, each of which is internally represented as an nvlist.
 420  */
 421 nwam_error_t
 422 nwam_next_object_list(void *parentlist, char *lastname, char **childnamep,
 423     void *childlistp)
 424 {
 425         nvpair_t *last = NULL, *next;
 426         int nverr;
 427 
 428         if (lastname != NULL) {
 429                 if ((nverr = nvlist_lookup_nvpair(parentlist, lastname, &last))
 430                     != 0)
 431                         return (nwam_errno_to_nwam_error(nverr));
 432         }
 433         if ((next = nvlist_next_nvpair(parentlist, last)) == NULL)
 434                 return (NWAM_LIST_END);
 435 
 436         *childnamep = nvpair_name(next);
 437 
 438         if (nvpair_type(next) != DATA_TYPE_NVLIST)
 439                 return (NWAM_ERROR_INTERNAL);
 440 
 441         if ((nverr = nvpair_value_nvlist(next, childlistp)) != NWAM_SUCCESS)
 442                 return (nwam_errno_to_nwam_error(nverr));
 443 
 444         return (NWAM_SUCCESS);
 445 }
 446 
 447 /*
 448  * Pack nvlist into contiguous memory. If packed_listp is NULL, we just
 449  * return the size of the memory needed to do so.
 450  */
 451 nwam_error_t
 452 nwam_pack_object_list(void *list, char **packed_listp, size_t *packed_sizep)
 453 {
 454         int nverr;
 455 
 456         assert(list != NULL && packed_sizep != NULL);
 457 
 458         if (packed_listp == NULL) {
 459                 nverr = nvlist_size(list, packed_sizep, NV_ENCODE_XDR);
 460         } else {
 461                 nverr = nvlist_pack(list, packed_listp, packed_sizep,
 462                     NV_ENCODE_XDR, 0);
 463         }
 464 
 465         if (nverr != 0)
 466                 return (nwam_errno_to_nwam_error(nverr));
 467 
 468         return (NWAM_SUCCESS);
 469 }
 470 
 471 nwam_error_t
 472 nwam_unpack_object_list(char *packed_list, size_t packed_size,
 473     void *list)
 474 {
 475         int nverr;
 476 
 477         assert(packed_list != NULL && list != NULL);
 478 
 479         *((nvlist_t **)list) = NULL;
 480 
 481         nverr = nvlist_unpack(packed_list, packed_size, (nvlist_t **)list, 0);
 482 
 483         if (nverr != 0)
 484                 return (nwam_errno_to_nwam_error(nverr));
 485 
 486         return (NWAM_SUCCESS);
 487 }
 488 
 489 /*
 490  * Functions to walk, set and get properties in nvlist, translating
 491  * between nwam_value_t and nvlist/nvpair representations.
 492  */
 493 nwam_error_t
 494 nwam_next_object_prop(void *list, char *lastname, char **namep,
 495     nwam_value_t *valuep)
 496 {
 497         nvpair_t *last = NULL, *next;
 498         int nverr;
 499 
 500         if (lastname != NULL) {
 501                 if ((nverr = nvlist_lookup_nvpair(list, lastname, &last)) != 0)
 502                         return (nwam_errno_to_nwam_error(nverr));
 503         }
 504         if ((next = nvlist_next_nvpair(list, last)) == NULL)
 505                 return (NWAM_LIST_END);
 506 
 507         *namep = nvpair_name(next);
 508 
 509         return (nwam_get_prop_value(list, (const char *)*namep, valuep));
 510 }
 511 
 512 nwam_error_t
 513 nwam_get_prop_value(void *list, const char *name, nwam_value_t *valuep)
 514 {
 515         nvpair_t *prop;
 516         nwam_error_t err;
 517         int nverr;
 518         boolean_t *valbool;
 519         int64_t *valint64;
 520         uint64_t *valuint64;
 521         char **valstr;
 522         uint_t numvalues;
 523 
 524         assert(valuep != NULL);
 525 
 526         *valuep = NULL;
 527 
 528         if ((nverr = nvlist_lookup_nvpair(list, name, &prop)) != 0) {
 529                 /* convert EINVAL to NOT_FOUND */
 530                 if (nverr == EINVAL)
 531                         return (NWAM_ENTITY_NOT_FOUND);
 532                 return (nwam_errno_to_nwam_error(nverr));
 533         }
 534 
 535         switch (nvpair_type(prop)) {
 536         case DATA_TYPE_BOOLEAN_ARRAY:
 537                 if ((nverr = nvpair_value_boolean_array(prop,
 538                     &valbool, &numvalues)) != 0)
 539                         return (nwam_errno_to_nwam_error(nverr));
 540                 if ((err = nwam_value_create_boolean_array(valbool, numvalues,
 541                     valuep)) != NWAM_SUCCESS)
 542                         return (err);
 543                 break;
 544         case DATA_TYPE_INT64_ARRAY:
 545                 if ((nverr = nvpair_value_int64_array(prop,
 546                     &valint64, &numvalues)) != 0)
 547                         return (nwam_errno_to_nwam_error(nverr));
 548                 if ((err = nwam_value_create_int64_array(valint64, numvalues,
 549                     valuep)) != NWAM_SUCCESS)
 550                         return (err);
 551                 break;
 552         case DATA_TYPE_UINT64_ARRAY:
 553                 if ((nverr = nvpair_value_uint64_array(prop,
 554                     &valuint64, &numvalues)) != 0)
 555                         return (nwam_errno_to_nwam_error(nverr));
 556                 if ((err = nwam_value_create_uint64_array(valuint64, numvalues,
 557                     valuep)) != NWAM_SUCCESS)
 558                         return (err);
 559                 break;
 560         case DATA_TYPE_STRING_ARRAY:
 561                 if ((nverr = nvpair_value_string_array(prop,
 562                     &valstr, &numvalues)) != 0)
 563                         return (nwam_errno_to_nwam_error(nverr));
 564                 if ((err = nwam_value_create_string_array(valstr, numvalues,
 565                     valuep)) != NWAM_SUCCESS)
 566                         return (err);
 567                 break;
 568         default:
 569                 /* Should not happen */
 570                 return (NWAM_ERROR_INTERNAL);
 571         }
 572         return (NWAM_SUCCESS);
 573 }
 574 
 575 nwam_error_t
 576 nwam_delete_prop(void *list, const char *name)
 577 {
 578         int nverr;
 579 
 580         if ((nverr = nvlist_remove_all(list, name)) != 0)
 581                 return (nwam_errno_to_nwam_error(nverr));
 582         return (NWAM_SUCCESS);
 583 }
 584 
 585 nwam_error_t
 586 nwam_set_prop_value(void *list, const char *propname, nwam_value_t value)
 587 {
 588         int nverr;
 589         nwam_error_t err;
 590         nwam_value_type_t type;
 591         uint_t numvalues;
 592         boolean_t *valbool;
 593         int64_t *valint64;
 594         uint64_t *valuint64;
 595         char **valstr;
 596 
 597         assert(list != NULL && value != NULL);
 598 
 599         if ((err = nwam_value_get_type(value, &type)) != NWAM_SUCCESS)
 600                 return (err);
 601 
 602         switch (type) {
 603         case NWAM_VALUE_TYPE_BOOLEAN:
 604                 if ((err = nwam_value_get_boolean_array(value, &valbool,
 605                     &numvalues)) != NWAM_SUCCESS)
 606                         return (err);
 607                 if ((nverr = nvlist_add_boolean_array(list, propname,
 608                     valbool, numvalues)) != 0)
 609                         return (nwam_errno_to_nwam_error(nverr));
 610                 break;
 611         case NWAM_VALUE_TYPE_INT64:
 612                 if ((err = nwam_value_get_int64_array(value, &valint64,
 613                     &numvalues)) != NWAM_SUCCESS)
 614                         return (err);
 615                 if ((nverr = nvlist_add_int64_array(list, propname,
 616                     valint64, numvalues)) != 0)
 617                         return (nwam_errno_to_nwam_error(nverr));
 618                 break;
 619         case NWAM_VALUE_TYPE_UINT64:
 620                 if ((err = nwam_value_get_uint64_array(value, &valuint64,
 621                     &numvalues)) != NWAM_SUCCESS)
 622                         return (err);
 623                 if ((nverr = nvlist_add_uint64_array(list, propname,
 624                     valuint64, numvalues)) != 0)
 625                         return (nwam_errno_to_nwam_error(nverr));
 626                 break;
 627         case NWAM_VALUE_TYPE_STRING:
 628                 if ((err = nwam_value_get_string_array(value, &valstr,
 629                     &numvalues)) != NWAM_SUCCESS)
 630                         return (err);
 631                 if ((nverr = nvlist_add_string_array(list, propname,
 632                     valstr, numvalues)) != 0)
 633                         return (nwam_errno_to_nwam_error(nverr));
 634                 break;
 635         default:
 636                 return (NWAM_INVALID_ARG);
 637         }
 638 
 639         return (NWAM_SUCCESS);
 640 }
 641 
 642 /* Map uint64 values to their string counterparts */
 643 
 644 struct nwam_value_entry {
 645         const char      *value_string;
 646         uint64_t                value;
 647 };
 648 
 649 struct nwam_value_entry prop_activation_mode_value_entries[] =
 650 {
 651         { NWAM_ACTIVATION_MODE_MANUAL_STRING, NWAM_ACTIVATION_MODE_MANUAL },
 652         { NWAM_ACTIVATION_MODE_SYSTEM_STRING, NWAM_ACTIVATION_MODE_SYSTEM },
 653         { NWAM_ACTIVATION_MODE_CONDITIONAL_ANY_STRING,
 654         NWAM_ACTIVATION_MODE_CONDITIONAL_ANY },
 655         { NWAM_ACTIVATION_MODE_CONDITIONAL_ALL_STRING,
 656         NWAM_ACTIVATION_MODE_CONDITIONAL_ALL },
 657         { NWAM_ACTIVATION_MODE_PRIORITIZED_STRING,
 658         NWAM_ACTIVATION_MODE_PRIORITIZED },
 659         { NULL, 0 }
 660 };
 661 
 662 struct nwam_value_entry ncu_prop_type_entries[] =
 663 {
 664         { NWAM_NCU_TYPE_LINK_STRING, NWAM_NCU_TYPE_LINK },
 665         { NWAM_NCU_TYPE_INTERFACE_STRING, NWAM_NCU_TYPE_INTERFACE },
 666         { NULL, 0 }
 667 };
 668 
 669 struct nwam_value_entry ncu_prop_class_entries[] =
 670 {
 671         { NWAM_NCU_CLASS_PHYS_STRING, NWAM_NCU_CLASS_PHYS },
 672         { NWAM_NCU_CLASS_IP_STRING, NWAM_NCU_CLASS_IP },
 673         { NULL, 0 }
 674 };
 675 
 676 struct nwam_value_entry ncu_prop_ip_version_entries[] =
 677 {
 678         { NWAM_IP_VERSION_IPV4_STRING, IPV4_VERSION },
 679         { NWAM_IP_VERSION_IPV6_STRING, IPV6_VERSION },
 680         { NULL, 0 }
 681 };
 682 
 683 struct nwam_value_entry ncu_prop_ipv4_addrsrc_entries[] =
 684 {
 685         { NWAM_ADDRSRC_DHCP_STRING, NWAM_ADDRSRC_DHCP },
 686         { NWAM_ADDRSRC_STATIC_STRING, NWAM_ADDRSRC_STATIC },
 687         { NULL, 0 }
 688 };
 689 
 690 struct nwam_value_entry ncu_prop_ipv6_addrsrc_entries[] =
 691 {
 692         { NWAM_ADDRSRC_DHCP_STRING, NWAM_ADDRSRC_DHCP },
 693         { NWAM_ADDRSRC_STATIC_STRING, NWAM_ADDRSRC_STATIC },
 694         { NWAM_ADDRSRC_AUTOCONF_STRING, NWAM_ADDRSRC_AUTOCONF },
 695         { NULL, 0 }
 696 };
 697 
 698 struct nwam_value_entry ncu_prop_priority_mode_entries[] =
 699 {
 700         { NWAM_PRIORITY_MODE_EXCLUSIVE_STRING, NWAM_PRIORITY_MODE_EXCLUSIVE },
 701         { NWAM_PRIORITY_MODE_SHARED_STRING, NWAM_PRIORITY_MODE_SHARED },
 702         { NWAM_PRIORITY_MODE_ALL_STRING, NWAM_PRIORITY_MODE_ALL },
 703         { NULL, 0 }
 704 };
 705 
 706 struct nwam_value_entry loc_prop_nameservices_entries[] =
 707 {
 708         { NWAM_NAMESERVICES_DNS_STRING, NWAM_NAMESERVICES_DNS },
 709         { NWAM_NAMESERVICES_FILES_STRING, NWAM_NAMESERVICES_FILES },
 710         { NWAM_NAMESERVICES_NIS_STRING, NWAM_NAMESERVICES_NIS },
 711         { NWAM_NAMESERVICES_LDAP_STRING, NWAM_NAMESERVICES_LDAP },
 712         { NULL, 0 }
 713 };
 714 
 715 struct nwam_value_entry loc_prop_nameservice_configsrc_entries[] =
 716 {
 717         { NWAM_CONFIGSRC_MANUAL_STRING, NWAM_CONFIGSRC_MANUAL },
 718         { NWAM_CONFIGSRC_DHCP_STRING, NWAM_CONFIGSRC_DHCP },
 719         { NULL, 0 }
 720 };
 721 
 722 struct nwam_value_entry known_wlan_prop_security_mode_entries[] =
 723 {
 724         { "none", DLADM_WLAN_SECMODE_NONE },
 725         { "wep", DLADM_WLAN_SECMODE_WEP },
 726         { "wpa", DLADM_WLAN_SECMODE_WPA },
 727         { NULL, 0 }
 728 };
 729 
 730 struct nwam_prop_value_entry {
 731         const char              *prop_name;
 732         struct nwam_value_entry *value_entries;
 733 } prop_value_entry_table[] =
 734 {
 735         { NWAM_NCU_PROP_ACTIVATION_MODE, prop_activation_mode_value_entries },
 736         { NWAM_NCU_PROP_TYPE, ncu_prop_type_entries },
 737         { NWAM_NCU_PROP_CLASS, ncu_prop_class_entries },
 738         { NWAM_NCU_PROP_IP_VERSION, ncu_prop_ip_version_entries },
 739         { NWAM_NCU_PROP_IPV4_ADDRSRC, ncu_prop_ipv4_addrsrc_entries },
 740         { NWAM_NCU_PROP_IPV6_ADDRSRC, ncu_prop_ipv6_addrsrc_entries },
 741         { NWAM_NCU_PROP_PRIORITY_MODE, ncu_prop_priority_mode_entries },
 742         { NWAM_ENM_PROP_ACTIVATION_MODE, prop_activation_mode_value_entries },
 743         { NWAM_LOC_PROP_ACTIVATION_MODE, prop_activation_mode_value_entries },
 744         { NWAM_LOC_PROP_NAMESERVICES, loc_prop_nameservices_entries },
 745         { NWAM_LOC_PROP_DNS_NAMESERVICE_CONFIGSRC,
 746             loc_prop_nameservice_configsrc_entries },
 747         { NWAM_LOC_PROP_NIS_NAMESERVICE_CONFIGSRC,
 748             loc_prop_nameservice_configsrc_entries },
 749         { NWAM_LOC_PROP_LDAP_NAMESERVICE_CONFIGSRC,
 750             loc_prop_nameservice_configsrc_entries },
 751         { NWAM_KNOWN_WLAN_PROP_SECURITY_MODE,
 752             known_wlan_prop_security_mode_entries },
 753         { NULL, NULL }
 754 };
 755 
 756 /*
 757  * Convert uint64 values for property propname into a string representing
 758  * that value. Used by enum values.
 759  */
 760 nwam_error_t
 761 nwam_uint64_get_value_string(const char *propname, uint64_t val,
 762     const char **valstrp)
 763 {
 764         int i, j;
 765         int max = 0; /* largest enum value seen so far */
 766         struct nwam_value_entry *value_entries;
 767 
 768         assert(propname != NULL && valstrp != NULL);
 769 
 770         for (i = 0; prop_value_entry_table[i].prop_name != NULL; i++) {
 771                 if (strcmp(prop_value_entry_table[i].prop_name, propname) != 0)
 772                         continue;
 773 
 774                 value_entries = prop_value_entry_table[i].value_entries;
 775 
 776                 for (j = 0; value_entries[j].value_string != NULL; j++) {
 777                         if (value_entries[j].value == val) {
 778                                 *valstrp = value_entries[j].value_string;
 779                                 return (NWAM_SUCCESS);
 780                         }
 781                         max = value_entries[j].value > max ?
 782                             value_entries[j].value : max;
 783                 }
 784                 /*
 785                  * If trying to get the string for an enum value that doesn't
 786                  * exist, return NWAM_LIST_END.  Otherwise, the input enum
 787                  * value doesn't exist for the given property.
 788                  */
 789                 if (val > max)
 790                         return (NWAM_LIST_END);
 791                 else
 792                         return (NWAM_ENTITY_INVALID_VALUE);
 793         }
 794         return (NWAM_INVALID_ARG);
 795 }
 796 
 797 /*
 798  * Convert string to appropriate uint64 value.
 799  */
 800 nwam_error_t
 801 nwam_value_string_get_uint64(const char *propname, const char *valstr,
 802     uint64_t *valp)
 803 {
 804         int i, j;
 805         struct nwam_value_entry *value_entries;
 806 
 807         assert(propname != NULL && valstr != NULL && valp != NULL);
 808 
 809         for (i = 0; prop_value_entry_table[i].prop_name != NULL; i++) {
 810                 if (strcmp(prop_value_entry_table[i].prop_name, propname) != 0)
 811                         continue;
 812 
 813                 value_entries = prop_value_entry_table[i].value_entries;
 814 
 815                 for (j = 0; value_entries[j].value_string != NULL; j++) {
 816                         if (strcasecmp(value_entries[j].value_string, valstr)
 817                             == 0) {
 818                                 *valp = value_entries[j].value;
 819                                 return (NWAM_SUCCESS);
 820                         }
 821                 }
 822                 return (NWAM_ENTITY_INVALID_VALUE);
 823         }
 824         return (NWAM_INVALID_ARG);
 825 }
 826 
 827 /* Conditional activation functions */
 828 
 829 nwam_error_t
 830 nwam_condition_to_condition_string(nwam_condition_object_type_t object_type,
 831     nwam_condition_t condition, const char *object_name, char **stringp)
 832 {
 833         char *object_type_string, *condition_string;
 834         char *string;
 835 
 836         assert(stringp != NULL);
 837 
 838         *stringp = NULL;
 839 
 840         switch (object_type) {
 841         case NWAM_CONDITION_OBJECT_TYPE_NCP:
 842                 object_type_string = NWAM_CONDITION_OBJECT_TYPE_NCP_STRING;
 843                 break;
 844         case NWAM_CONDITION_OBJECT_TYPE_NCU:
 845                 object_type_string = NWAM_CONDITION_OBJECT_TYPE_NCU_STRING;
 846                 break;
 847         case NWAM_CONDITION_OBJECT_TYPE_ENM:
 848                 object_type_string = NWAM_CONDITION_OBJECT_TYPE_ENM_STRING;
 849                 break;
 850         case NWAM_CONDITION_OBJECT_TYPE_LOC:
 851                 object_type_string = NWAM_CONDITION_OBJECT_TYPE_LOC_STRING;
 852                 break;
 853         case NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS:
 854                 object_type_string =
 855                     NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS_STRING;
 856                 break;
 857         case NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN:
 858                 object_type_string =
 859                     NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN_STRING;
 860                 break;
 861         case NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN:
 862                 object_type_string =
 863                     NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN_STRING;
 864                 break;
 865         case NWAM_CONDITION_OBJECT_TYPE_ESSID:
 866                 object_type_string = NWAM_CONDITION_OBJECT_TYPE_ESSID_STRING;
 867                 break;
 868         case NWAM_CONDITION_OBJECT_TYPE_BSSID:
 869                 object_type_string = NWAM_CONDITION_OBJECT_TYPE_BSSID_STRING;
 870                 break;
 871         default:
 872                 return (NWAM_INVALID_ARG);
 873 
 874         }
 875         switch (condition) {
 876         case NWAM_CONDITION_IS:
 877                 condition_string = NWAM_CONDITION_IS_STRING;
 878                 break;
 879         case NWAM_CONDITION_IS_NOT:
 880                 condition_string = NWAM_CONDITION_IS_NOT_STRING;
 881                 break;
 882         case NWAM_CONDITION_CONTAINS:
 883                 if (object_type != NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN &&
 884                     object_type != NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN &&
 885                     object_type != NWAM_CONDITION_OBJECT_TYPE_ESSID)
 886                         return (NWAM_INVALID_ARG);
 887                 condition_string = NWAM_CONDITION_CONTAINS_STRING;
 888                 break;
 889         case NWAM_CONDITION_DOES_NOT_CONTAIN:
 890                 if (object_type != NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN &&
 891                     object_type != NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN &&
 892                     object_type != NWAM_CONDITION_OBJECT_TYPE_ESSID)
 893                         return (NWAM_INVALID_ARG);
 894 
 895                 condition_string = NWAM_CONDITION_DOES_NOT_CONTAIN_STRING;
 896                 break;
 897         case NWAM_CONDITION_IS_IN_RANGE:
 898                 if (object_type != NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS)
 899                         return (NWAM_INVALID_ARG);
 900                 condition_string = NWAM_CONDITION_IS_IN_RANGE_STRING;
 901                 break;
 902         case NWAM_CONDITION_IS_NOT_IN_RANGE:
 903                 if (object_type != NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS)
 904                         return (NWAM_INVALID_ARG);
 905                 condition_string = NWAM_CONDITION_IS_NOT_IN_RANGE_STRING;
 906                 break;
 907         default:
 908                 return (NWAM_INVALID_ARG);
 909         }
 910         if ((string = malloc(NWAM_MAX_VALUE_LEN)) == NULL)
 911                 return (NWAM_NO_MEMORY);
 912         switch (object_type) {
 913         case NWAM_CONDITION_OBJECT_TYPE_NCP:
 914         case NWAM_CONDITION_OBJECT_TYPE_NCU:
 915         case NWAM_CONDITION_OBJECT_TYPE_ENM:
 916         case NWAM_CONDITION_OBJECT_TYPE_LOC:
 917                 (void) snprintf(string, NWAM_MAX_VALUE_LEN,
 918                     "%s %s %s active", object_type_string,
 919                     object_name, condition_string);
 920                 *stringp = string;
 921                 break;
 922 
 923         case NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS:
 924         case NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN:
 925         case NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN:
 926         case NWAM_CONDITION_OBJECT_TYPE_ESSID:
 927         case NWAM_CONDITION_OBJECT_TYPE_BSSID:
 928                 (void) snprintf(string, NWAM_MAX_VALUE_LEN,
 929                     "%s %s %s", object_type_string,
 930                     condition_string, object_name);
 931                 *stringp = string;
 932                 break;
 933 
 934         default:
 935                 free(string);
 936                 return (NWAM_INVALID_ARG);
 937 
 938         }
 939         return (NWAM_SUCCESS);
 940 }
 941 
 942 nwam_error_t
 943 nwam_condition_string_to_condition(const char *string,
 944     nwam_condition_object_type_t *object_typep,
 945     nwam_condition_t *conditionp, char **object_namep)
 946 {
 947         char *copy, *lasts;
 948         char *object_type_string, *object_name;
 949         char *condition_string, *active_string;
 950 
 951         assert(string != NULL && object_typep != NULL && conditionp != NULL &&
 952             object_namep != NULL);
 953 
 954         if ((copy = strdup(string)) == NULL)
 955                 return (NWAM_NO_MEMORY);
 956 
 957         if ((object_type_string = strtok_r(copy, " \t", &lasts)) == NULL) {
 958                 free(copy);
 959                 return (NWAM_INVALID_ARG);
 960         }
 961 
 962         if (strcmp(object_type_string, NWAM_CONDITION_OBJECT_TYPE_NCP_STRING)
 963             == 0)
 964                 *object_typep = NWAM_CONDITION_OBJECT_TYPE_NCP;
 965         else if (strcmp(object_type_string,
 966             NWAM_CONDITION_OBJECT_TYPE_NCU_STRING) == 0)
 967                 *object_typep = NWAM_CONDITION_OBJECT_TYPE_NCU;
 968         else if (strcmp(object_type_string,
 969             NWAM_CONDITION_OBJECT_TYPE_ENM_STRING) == 0)
 970                 *object_typep = NWAM_CONDITION_OBJECT_TYPE_ENM;
 971         else if (strcmp(object_type_string,
 972             NWAM_CONDITION_OBJECT_TYPE_LOC_STRING) == 0)
 973                 *object_typep = NWAM_CONDITION_OBJECT_TYPE_LOC;
 974         else if (strcmp(object_type_string,
 975             NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS_STRING) == 0)
 976                 *object_typep = NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS;
 977         else if (strcmp(object_type_string,
 978             NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN_STRING) == 0)
 979                 *object_typep = NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN;
 980         else if (strcmp(object_type_string,
 981             NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN_STRING) == 0)
 982                 *object_typep = NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN;
 983         else if (strcmp(object_type_string,
 984             NWAM_CONDITION_OBJECT_TYPE_ESSID_STRING) == 0)
 985                 *object_typep = NWAM_CONDITION_OBJECT_TYPE_ESSID;
 986         else if (strcmp(object_type_string,
 987             NWAM_CONDITION_OBJECT_TYPE_BSSID_STRING) == 0)
 988                 *object_typep = NWAM_CONDITION_OBJECT_TYPE_BSSID;
 989         else {
 990                 free(copy);
 991                 return (NWAM_INVALID_ARG);
 992         }
 993 
 994         if (*object_typep == NWAM_CONDITION_OBJECT_TYPE_NCP ||
 995             *object_typep == NWAM_CONDITION_OBJECT_TYPE_NCU ||
 996             *object_typep == NWAM_CONDITION_OBJECT_TYPE_ENM ||
 997             *object_typep == NWAM_CONDITION_OBJECT_TYPE_LOC) {
 998                 if ((object_name = strtok_r(NULL, " \t", &lasts)) == NULL) {
 999                         free(copy);
1000                         return (NWAM_INVALID_ARG);
1001                 }
1002                 if ((*object_namep = strdup(object_name)) == NULL) {
1003                         free(copy);
1004                         return (NWAM_NO_MEMORY);
1005                 }
1006 
1007         }
1008 
1009         if ((condition_string = strtok_r(NULL, " \t", &lasts)) == NULL) {
1010                 free(copy);
1011                 if (*object_namep != NULL)
1012                         free(*object_namep);
1013                 return (NWAM_INVALID_ARG);
1014         }
1015         if (strcmp(condition_string, NWAM_CONDITION_IS_STRING) == 0)
1016                 *conditionp = NWAM_CONDITION_IS;
1017         else if (strcmp(condition_string, NWAM_CONDITION_IS_NOT_STRING) == 0)
1018                 *conditionp = NWAM_CONDITION_IS_NOT;
1019         else if (strcmp(condition_string, NWAM_CONDITION_CONTAINS_STRING) == 0)
1020                 *conditionp = NWAM_CONDITION_CONTAINS;
1021         else if (strcmp(condition_string,
1022             NWAM_CONDITION_DOES_NOT_CONTAIN_STRING) == 0)
1023                 *conditionp = NWAM_CONDITION_DOES_NOT_CONTAIN;
1024         else if (strcmp(condition_string,
1025             NWAM_CONDITION_IS_IN_RANGE_STRING) == 0)
1026                 *conditionp = NWAM_CONDITION_IS_IN_RANGE;
1027         else if (strcmp(condition_string,
1028             NWAM_CONDITION_IS_NOT_IN_RANGE_STRING) == 0)
1029                 *conditionp = NWAM_CONDITION_IS_NOT_IN_RANGE;
1030         else {
1031                 free(copy);
1032                 if (*object_namep != NULL)
1033                         free(*object_namep);
1034                 return (NWAM_INVALID_ARG);
1035         }
1036 
1037         if (*object_typep == NWAM_CONDITION_OBJECT_TYPE_NCP ||
1038             *object_typep == NWAM_CONDITION_OBJECT_TYPE_NCU ||
1039             *object_typep == NWAM_CONDITION_OBJECT_TYPE_ENM ||
1040             *object_typep == NWAM_CONDITION_OBJECT_TYPE_LOC) {
1041                 if ((*conditionp != NWAM_CONDITION_IS &&
1042                     *conditionp != NWAM_CONDITION_IS_NOT) ||
1043                     (active_string = strtok_r(NULL, " \t", &lasts)) == NULL ||
1044                     strcmp(active_string, NWAM_CONDITION_ACTIVE_STRING) != 0) {
1045                         free(copy);
1046                         free(*object_namep);
1047                         return (NWAM_INVALID_ARG);
1048                 }
1049         } else {
1050                 switch (*conditionp) {
1051                 case NWAM_CONDITION_CONTAINS:
1052                 case NWAM_CONDITION_DOES_NOT_CONTAIN:
1053                         if (*object_typep !=
1054                             NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN &&
1055                             *object_typep !=
1056                             NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN &&
1057                             *object_typep != NWAM_CONDITION_OBJECT_TYPE_ESSID) {
1058                                 free(copy);
1059                                 free(*object_namep);
1060                                 return (NWAM_INVALID_ARG);
1061                         }
1062                         break;
1063                 case NWAM_CONDITION_IS_IN_RANGE:
1064                 case NWAM_CONDITION_IS_NOT_IN_RANGE:
1065                         if (*object_typep !=
1066                             NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS) {
1067                                 free(copy);
1068                                 free(*object_namep);
1069                                 return (NWAM_INVALID_ARG);
1070                         }
1071                         break;
1072                 }
1073 
1074                 if ((object_name = strtok_r(NULL, " \t", &lasts)) == NULL) {
1075                         free(copy);
1076                         free(*object_namep);
1077                         return (NWAM_INVALID_ARG);
1078                 }
1079                 if ((*object_namep = strdup(object_name)) == NULL) {
1080                         free(copy);
1081                         free(*object_namep);
1082                         return (NWAM_NO_MEMORY);
1083                 }
1084         }
1085 
1086         free(copy);
1087         return (NWAM_SUCCESS);
1088 }
1089 
1090 nwam_error_t
1091 nwam_condition_rate(nwam_condition_object_type_t object_type,
1092     nwam_condition_t condition, uint64_t *ratep)
1093 {
1094         assert(ratep != NULL);
1095 
1096         *ratep = 0;
1097 
1098         switch (object_type) {
1099         case NWAM_CONDITION_OBJECT_TYPE_NCP:
1100         case NWAM_CONDITION_OBJECT_TYPE_NCU:
1101         case NWAM_CONDITION_OBJECT_TYPE_ENM:
1102         case NWAM_CONDITION_OBJECT_TYPE_LOC:
1103                 (*ratep)++;
1104                 /* FALLTHRU */
1105         case NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN:
1106                 (*ratep)++;
1107                 /* FALLTHRU */
1108         case NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN:
1109                 (*ratep)++;
1110                 /* FALLTHRU */
1111         case NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS:
1112                 (*ratep)++;
1113                 /* FALLTHRU */
1114         case NWAM_CONDITION_OBJECT_TYPE_BSSID:
1115                 (*ratep)++;
1116                 /* FALLTHRU */
1117         case NWAM_CONDITION_OBJECT_TYPE_ESSID:
1118                 (*ratep)++;
1119                 break;
1120         default:
1121                 return (NWAM_INVALID_ARG);
1122         }
1123 
1124         switch (condition) {
1125         case NWAM_CONDITION_IS:
1126                 (*ratep)++;
1127                 /* FALLTHRU */
1128         case NWAM_CONDITION_CONTAINS:
1129         case NWAM_CONDITION_IS_IN_RANGE:
1130                 (*ratep)++;
1131                 /* FALLTHRU */
1132         case NWAM_CONDITION_DOES_NOT_CONTAIN:
1133         case NWAM_CONDITION_IS_NOT_IN_RANGE:
1134                 (*ratep)++;
1135                 /* FALLTHRU */
1136         case NWAM_CONDITION_IS_NOT:
1137                 (*ratep)++;
1138                 break;
1139         default:
1140                 return (NWAM_INVALID_ARG);
1141         }
1142         return (NWAM_SUCCESS);
1143 }
--- EOF ---