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 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <assert.h> 28 #include <ctype.h> 29 #include <sys/param.h> 30 #include <sys/types.h> 31 #include <sys/stat.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <strings.h> 35 #include <unistd.h> 36 #include <libdllink.h> 37 #include <libdlwlan.h> 38 39 #include "libnwam_impl.h" 40 #include <libnwam_priv.h> 41 #include <libnwam.h> 42 43 /* 44 * Functions to support creating, modifying and destroying 45 * known WLAN objects. These represent the WiFi connection history, 46 * and are used by nwamd to identify and connect to known WLANs in 47 * scan results. 48 */ 49 50 static nwam_error_t valid_keyname(nwam_value_t); 51 static nwam_error_t valid_keyslot(nwam_value_t); 52 static nwam_error_t valid_secmode(nwam_value_t); 53 54 struct nwam_prop_table_entry known_wlan_prop_table_entries[] = { 55 {NWAM_KNOWN_WLAN_PROP_PRIORITY, NWAM_VALUE_TYPE_UINT64, B_FALSE, 56 1, 1, nwam_valid_uint64, 57 "specifies priority of known WLAN - lower values are prioritized", 58 NWAM_TYPE_ANY, NWAM_CLASS_ANY}, 59 {NWAM_KNOWN_WLAN_PROP_BSSIDS, NWAM_VALUE_TYPE_STRING, B_FALSE, 60 0, NWAM_MAX_NUM_VALUES, nwam_valid_mac_addr, 61 "specifies BSSID(s) (of the form aa:bb:cc:dd:ee:ff) associated " 62 "with known WLAN", 63 NWAM_TYPE_ANY, NWAM_CLASS_ANY}, 64 {NWAM_KNOWN_WLAN_PROP_KEYNAME, NWAM_VALUE_TYPE_STRING, B_FALSE, 65 0, 1, valid_keyname, 66 "specifies security key name used with known WLAN", 67 NWAM_TYPE_ANY, NWAM_CLASS_ANY}, 68 {NWAM_KNOWN_WLAN_PROP_KEYSLOT, NWAM_VALUE_TYPE_UINT64, B_FALSE, 69 0, 1, valid_keyslot, 70 "specifies key slot [1-4] for security key used with known WLAN", 71 NWAM_TYPE_ANY, NWAM_CLASS_ANY}, 72 {NWAM_KNOWN_WLAN_PROP_SECURITY_MODE, NWAM_VALUE_TYPE_UINT64, B_FALSE, 73 0, 1, valid_secmode, 74 "specifies security mode used for known WLAN", 75 NWAM_TYPE_ANY, NWAM_CLASS_ANY} 76 }; 77 78 #define NWAM_NUM_KNOWN_WLAN_PROPS \ 79 (sizeof (known_wlan_prop_table_entries) / \ 80 sizeof (*known_wlan_prop_table_entries)) 81 82 struct nwam_prop_table known_wlan_prop_table = 83 { NWAM_NUM_KNOWN_WLAN_PROPS, known_wlan_prop_table_entries }; 84 85 nwam_error_t 86 nwam_known_wlan_read(const char *name, uint64_t flags, 87 nwam_known_wlan_handle_t *kwhp) 88 { 89 return (nwam_read(NWAM_OBJECT_TYPE_KNOWN_WLAN, 90 NWAM_KNOWN_WLAN_CONF_FILE, name, flags, kwhp)); 91 } 92 93 nwam_error_t 94 nwam_known_wlan_create(const char *name, nwam_known_wlan_handle_t *kwhp) 95 { 96 nwam_error_t err; 97 nwam_value_t priorityval = NULL; 98 99 assert(kwhp != NULL && name != NULL); 100 101 if ((err = nwam_create(NWAM_OBJECT_TYPE_KNOWN_WLAN, 102 NWAM_KNOWN_WLAN_CONF_FILE, name, kwhp)) != NWAM_SUCCESS) 103 return (err); 104 105 /* 106 * Create new object list for known WLAN. The initial priority is 107 * also set. 108 */ 109 if ((err = nwam_alloc_object_list(&((*kwhp)->nwh_data))) 110 != NWAM_SUCCESS) 111 goto finish; 112 if ((err = nwam_value_create_uint64(0, &priorityval)) != NWAM_SUCCESS) 113 goto finish; 114 err = nwam_set_prop_value((*kwhp)->nwh_data, 115 NWAM_KNOWN_WLAN_PROP_PRIORITY, priorityval); 116 117 finish: 118 nwam_value_free(priorityval); 119 if (err != NWAM_SUCCESS) { 120 nwam_known_wlan_free(*kwhp); 121 *kwhp = NULL; 122 } 123 return (err); 124 } 125 126 nwam_error_t 127 nwam_known_wlan_get_name(nwam_known_wlan_handle_t kwh, char **namep) 128 { 129 return (nwam_get_name(kwh, namep)); 130 } 131 132 nwam_error_t 133 nwam_known_wlan_set_name(nwam_known_wlan_handle_t kwh, const char *name) 134 { 135 return (nwam_set_name(kwh, name)); 136 } 137 138 boolean_t 139 nwam_known_wlan_can_set_name(nwam_known_wlan_handle_t kwh) 140 { 141 return (!kwh->nwh_committed); 142 } 143 144 /* 145 * Used to store wlan names/priorities for prioritized walk. 146 */ 147 struct nwam_wlan_info { 148 char *wlan_name; 149 uint64_t wlan_priority; 150 boolean_t wlan_walked; 151 }; 152 153 struct nwam_wlan_info_list { 154 struct nwam_wlan_info **list; 155 uint_t num_wlans; 156 }; 157 158 /* 159 * Used to read in each known WLAN name/priority. 160 */ 161 static int 162 get_wlans_cb(nwam_known_wlan_handle_t kwh, void *data) 163 { 164 struct nwam_wlan_info_list *wil = data; 165 struct nwam_wlan_info **list = wil->list; 166 struct nwam_wlan_info **newlist = NULL; 167 nwam_error_t err; 168 nwam_value_t priorityval = NULL; 169 uint_t num_wlans = wil->num_wlans; 170 171 /* Reallocate WLAN list and allocate new info list element. */ 172 if ((newlist = realloc(list, 173 sizeof (struct nwam_wlan_info *) * ++num_wlans)) == NULL || 174 (newlist[num_wlans - 1] = calloc(1, 175 sizeof (struct nwam_wlan_info))) == NULL) { 176 if (newlist != NULL) 177 free(newlist); 178 return (NWAM_NO_MEMORY); 179 } 180 181 /* Update list since realloc() may have relocated it */ 182 wil->list = newlist; 183 184 /* Retrieve name/priority */ 185 if ((err = nwam_known_wlan_get_name(kwh, 186 &((newlist[num_wlans - 1])->wlan_name))) != NWAM_SUCCESS || 187 (err = nwam_known_wlan_get_prop_value(kwh, 188 NWAM_KNOWN_WLAN_PROP_PRIORITY, &priorityval)) != NWAM_SUCCESS || 189 (err = nwam_value_get_uint64(priorityval, 190 &((newlist[num_wlans - 1])->wlan_priority))) != NWAM_SUCCESS) { 191 free(newlist[num_wlans - 1]->wlan_name); 192 nwam_value_free(priorityval); 193 free(newlist[num_wlans - 1]); 194 return (err); 195 } 196 nwam_value_free(priorityval); 197 198 (newlist[num_wlans - 1])->wlan_walked = B_FALSE; 199 200 wil->num_wlans = num_wlans; 201 202 return (NWAM_SUCCESS); 203 } 204 205 /* 206 * Some recursion is required here, since if _WALK_PRIORITY_ORDER is specified, 207 * we need to first walk the list of known WLANs to retrieve names 208 * and priorities, then utilize that list to carry out an in-order walk. 209 */ 210 nwam_error_t 211 nwam_walk_known_wlans(int(*cb)(nwam_known_wlan_handle_t, void *), void *data, 212 uint64_t flags, int *retp) 213 { 214 nwam_known_wlan_handle_t kwh; 215 nwam_error_t err; 216 int ret = 0; 217 218 assert(cb != NULL); 219 220 if ((err = nwam_valid_flags(flags, 221 NWAM_FLAG_KNOWN_WLAN_WALK_PRIORITY_ORDER | NWAM_FLAG_BLOCKING)) 222 != NWAM_SUCCESS) 223 return (err); 224 225 if ((flags & NWAM_FLAG_KNOWN_WLAN_WALK_PRIORITY_ORDER) != 0) { 226 struct nwam_wlan_info_list wil = { NULL, 0}; 227 uint64_t iflags = flags &~ 228 NWAM_FLAG_KNOWN_WLAN_WALK_PRIORITY_ORDER; 229 uint64_t minpriority; 230 int errval, i, j, minindex; 231 232 if (nwam_walk_known_wlans(get_wlans_cb, &wil, iflags, &errval) 233 != NWAM_SUCCESS) { 234 err = (nwam_error_t)errval; 235 goto done; 236 } 237 238 err = NWAM_SUCCESS; 239 240 for (i = 0; i < wil.num_wlans; i++) { 241 /* Find lowest priority value not walked so far. */ 242 minpriority = (uint64_t)-1; 243 for (j = 0; j < wil.num_wlans; j++) { 244 if (wil.list[j]->wlan_priority < minpriority && 245 !(wil.list[j]->wlan_walked)) { 246 minpriority = 247 wil.list[j]->wlan_priority; 248 minindex = j; 249 } 250 } 251 wil.list[minindex]->wlan_walked = B_TRUE; 252 if ((err = nwam_known_wlan_read 253 (wil.list[minindex]->wlan_name, 254 iflags, &kwh)) != NWAM_SUCCESS) { 255 goto done; 256 } 257 ret = cb(kwh, data); 258 if (ret != 0) { 259 nwam_known_wlan_free(kwh); 260 err = NWAM_WALK_HALTED; 261 goto done; 262 } 263 nwam_known_wlan_free(kwh); 264 } 265 done: 266 if (wil.list != NULL) { 267 for (j = 0; j < wil.num_wlans; j++) { 268 free(wil.list[j]->wlan_name); 269 free(wil.list[j]); 270 } 271 free(wil.list); 272 } 273 if (retp != NULL) 274 *retp = ret; 275 return (err); 276 } 277 278 return (nwam_walk(NWAM_OBJECT_TYPE_KNOWN_WLAN, 279 NWAM_KNOWN_WLAN_CONF_FILE, cb, data, flags, retp, NULL)); 280 } 281 282 void 283 nwam_known_wlan_free(nwam_known_wlan_handle_t kwh) 284 { 285 nwam_free(kwh); 286 } 287 288 nwam_error_t 289 nwam_known_wlan_copy(nwam_known_wlan_handle_t oldkwh, const char *newname, 290 nwam_known_wlan_handle_t *newkwhp) 291 { 292 return (nwam_copy(NWAM_KNOWN_WLAN_CONF_FILE, oldkwh, newname, newkwhp)); 293 } 294 295 nwam_error_t 296 nwam_known_wlan_delete_prop(nwam_known_wlan_handle_t kwh, const char *propname) 297 { 298 nwam_error_t err; 299 void *olddata; 300 301 assert(kwh != NULL && propname != NULL); 302 303 /* 304 * Duplicate data, remove property and validate. If validation 305 * fails, revert to data duplicated prior to remove. 306 */ 307 if ((err = nwam_dup_object_list(kwh->nwh_data, &olddata)) 308 != NWAM_SUCCESS) 309 return (err); 310 if ((err = nwam_delete_prop(kwh->nwh_data, propname)) != NWAM_SUCCESS) { 311 nwam_free_object_list(kwh->nwh_data); 312 kwh->nwh_data = olddata; 313 return (err); 314 } 315 if ((err = nwam_known_wlan_validate(kwh, NULL)) != NWAM_SUCCESS) { 316 nwam_free_object_list(kwh->nwh_data); 317 kwh->nwh_data = olddata; 318 return (err); 319 } 320 nwam_free_object_list(olddata); 321 322 return (NWAM_SUCCESS); 323 } 324 325 nwam_error_t 326 nwam_known_wlan_set_prop_value(nwam_known_wlan_handle_t kwh, 327 const char *propname, nwam_value_t value) 328 { 329 nwam_error_t err; 330 331 assert(kwh != NULL && propname != NULL && value != NULL); 332 333 if ((err = nwam_known_wlan_validate_prop(kwh, propname, value)) 334 != NWAM_SUCCESS) 335 return (err); 336 337 return (nwam_set_prop_value(kwh->nwh_data, propname, value)); 338 } 339 340 nwam_error_t 341 nwam_known_wlan_get_prop_value(nwam_known_wlan_handle_t kwh, 342 const char *propname, nwam_value_t *valuep) 343 { 344 return (nwam_get_prop_value(kwh->nwh_data, propname, valuep)); 345 } 346 347 nwam_error_t 348 nwam_known_wlan_walk_props(nwam_known_wlan_handle_t kwh, 349 int (*cb)(const char *, nwam_value_t, void *), 350 void *data, uint64_t flags, int *retp) 351 { 352 return (nwam_walk_props(kwh, cb, data, flags, retp)); 353 } 354 355 struct priority_collision_data { 356 char *wlan_name; 357 uint64_t priority; 358 }; 359 360 static int 361 avoid_priority_collisions_cb(nwam_known_wlan_handle_t kwh, void *data) 362 { 363 nwam_value_t priorityval; 364 nwam_error_t err; 365 struct priority_collision_data *pcd = data; 366 char *name; 367 uint64_t priority; 368 369 err = nwam_known_wlan_get_name(kwh, &name); 370 if (err != NWAM_SUCCESS) 371 return (err); 372 if (strcmp(name, pcd->wlan_name) == 0) { 373 /* skip to-be-updated wlan */ 374 free(name); 375 return (NWAM_SUCCESS); 376 } 377 free(name); 378 379 err = nwam_known_wlan_get_prop_value(kwh, NWAM_KNOWN_WLAN_PROP_PRIORITY, 380 &priorityval); 381 if (err != NWAM_SUCCESS) 382 return (err); 383 err = nwam_value_get_uint64(priorityval, &priority); 384 if (err != NWAM_SUCCESS) 385 return (err); 386 nwam_value_free(priorityval); 387 388 if (priority < pcd->priority) 389 return (NWAM_SUCCESS); 390 391 if (priority == pcd->priority) { 392 /* Two priority values collide. Move this one up. */ 393 err = nwam_value_create_uint64(priority + 1, &priorityval); 394 if (err != NWAM_SUCCESS) 395 return (err); 396 err = nwam_known_wlan_set_prop_value(kwh, 397 NWAM_KNOWN_WLAN_PROP_PRIORITY, priorityval); 398 nwam_value_free(priorityval); 399 if (err != NWAM_SUCCESS) { 400 return (err); 401 } 402 /* 403 * We are doing a walk, and will continue shifting until 404 * we find a gap in the priority numbers; thus no need to 405 * do collision checking here. 406 */ 407 err = nwam_known_wlan_commit(kwh, 408 NWAM_FLAG_KNOWN_WLAN_NO_COLLISION_CHECK); 409 if (err != NWAM_SUCCESS) 410 return (err); 411 412 (pcd->priority)++; 413 return (NWAM_SUCCESS); 414 } 415 416 /* 417 * Only possiblity left at this point is that we're looking 418 * at a priority greater than the last one we wrote, so we've 419 * found a gap. We can halt the walk now. 420 */ 421 return (NWAM_WALK_HALTED); 422 } 423 424 nwam_error_t 425 nwam_known_wlan_commit(nwam_known_wlan_handle_t kwh, uint64_t flags) 426 { 427 nwam_error_t err; 428 nwam_value_t priorityval; 429 int ret = 0; 430 struct priority_collision_data pcd; 431 432 assert(kwh != NULL && kwh->nwh_data != NULL); 433 434 if ((err = nwam_known_wlan_validate(kwh, NULL)) != NWAM_SUCCESS) 435 return (err); 436 437 /* 438 * If the NO_COLLISION_CHECK flag is set, no need to check for 439 * collision. 440 */ 441 if (flags & NWAM_FLAG_KNOWN_WLAN_NO_COLLISION_CHECK) 442 return (nwam_commit(NWAM_KNOWN_WLAN_CONF_FILE, kwh, 443 (flags & NWAM_FLAG_GLOBAL_MASK) | 444 NWAM_FLAG_ENTITY_KNOWN_WLAN)); 445 446 /* 447 * We need to do priority checking. Walk the list, looking 448 * for the first entry with priority greater than or equal 449 * to the entry we're adding. Commit the new one (without 450 * doing additional checking), and then increment other 451 * entries as needed. 452 */ 453 err = nwam_known_wlan_get_prop_value(kwh, 454 NWAM_KNOWN_WLAN_PROP_PRIORITY, &priorityval); 455 if (err != NWAM_SUCCESS) 456 return (err); 457 err = nwam_value_get_uint64(priorityval, &(pcd.priority)); 458 nwam_value_free(priorityval); 459 if (err != NWAM_SUCCESS) 460 return (err); 461 err = nwam_known_wlan_get_name(kwh, &(pcd.wlan_name)); 462 if (err != NWAM_SUCCESS) 463 return (err); 464 err = nwam_walk_known_wlans(avoid_priority_collisions_cb, &pcd, 465 NWAM_FLAG_KNOWN_WLAN_WALK_PRIORITY_ORDER, &ret); 466 free(pcd.wlan_name); 467 /* 468 * a halted walk is okay, it just means we didn't have 469 * to walk the entire list to resolve priorities 470 */ 471 if (ret != NWAM_SUCCESS && ret != NWAM_WALK_HALTED) 472 return (ret); 473 474 return (nwam_known_wlan_commit(kwh, 475 flags | NWAM_FLAG_KNOWN_WLAN_NO_COLLISION_CHECK)); 476 } 477 478 nwam_error_t 479 nwam_known_wlan_destroy(nwam_known_wlan_handle_t kwh, uint64_t flags) 480 { 481 return (nwam_destroy(NWAM_KNOWN_WLAN_CONF_FILE, kwh, 482 flags | NWAM_FLAG_ENTITY_KNOWN_WLAN)); 483 } 484 485 nwam_error_t 486 nwam_known_wlan_get_prop_description(const char *propname, 487 const char **descriptionp) 488 { 489 return (nwam_get_prop_description(known_wlan_prop_table, propname, 490 descriptionp)); 491 } 492 493 /* Property-specific value validation functions should go here. */ 494 495 static nwam_error_t 496 valid_keyname(nwam_value_t value) 497 { 498 char *keyname; 499 500 if (nwam_value_get_string(value, &keyname) != NWAM_SUCCESS) 501 return (NWAM_ENTITY_INVALID_VALUE); 502 503 if (!dladm_valid_secobj_name(keyname)) 504 return (NWAM_ENTITY_INVALID_VALUE); 505 506 return (NWAM_SUCCESS); 507 } 508 509 static nwam_error_t 510 valid_keyslot(nwam_value_t value) 511 { 512 uint64_t keyslot; 513 514 if (nwam_value_get_uint64(value, &keyslot) != NWAM_SUCCESS) 515 return (NWAM_ENTITY_INVALID_VALUE); 516 517 if (keyslot < 1 || keyslot > 4) 518 return (NWAM_ENTITY_INVALID_VALUE); 519 520 return (NWAM_SUCCESS); 521 } 522 523 static nwam_error_t 524 valid_secmode(nwam_value_t value) 525 { 526 uint64_t secmode; 527 528 if (nwam_value_get_uint64(value, &secmode) != NWAM_SUCCESS) 529 return (NWAM_ENTITY_INVALID_VALUE); 530 531 if (secmode != DLADM_WLAN_SECMODE_NONE && 532 secmode != DLADM_WLAN_SECMODE_WEP && 533 secmode != DLADM_WLAN_SECMODE_WPA) 534 return (NWAM_ENTITY_INVALID_VALUE); 535 536 return (NWAM_SUCCESS); 537 } 538 539 nwam_error_t 540 nwam_known_wlan_validate(nwam_known_wlan_handle_t kwh, const char **errpropp) 541 { 542 return (nwam_validate(known_wlan_prop_table, kwh, errpropp)); 543 } 544 545 nwam_error_t 546 nwam_known_wlan_validate_prop(nwam_known_wlan_handle_t kwh, 547 const char *propname, nwam_value_t value) 548 { 549 return (nwam_validate_prop(known_wlan_prop_table, kwh, propname, 550 value)); 551 } 552 553 /* 554 * Given a property, return expected property data type 555 */ 556 nwam_error_t 557 nwam_known_wlan_get_prop_type(const char *propname, nwam_value_type_t *typep) 558 { 559 return (nwam_get_prop_type(known_wlan_prop_table, propname, typep)); 560 } 561 562 nwam_error_t 563 nwam_known_wlan_prop_multivalued(const char *propname, boolean_t *multip) 564 { 565 return (nwam_prop_multivalued(known_wlan_prop_table, propname, multip)); 566 } 567 568 nwam_error_t 569 nwam_known_wlan_get_default_proplist(const char ***prop_list, 570 uint_t *numvaluesp) 571 { 572 return (nwam_get_default_proplist(known_wlan_prop_table, 573 NWAM_TYPE_ANY, NWAM_CLASS_ANY, prop_list, numvaluesp)); 574 } 575 576 /* 577 * Add the given ESSID, BSSID, secmode, keyslot and key name to known WLANs. 578 * BSSID and keyname can be NULL. 579 */ 580 nwam_error_t 581 nwam_known_wlan_add_to_known_wlans(const char *essid, const char *bssid, 582 uint32_t secmode, uint_t keyslot, const char *keyname) 583 { 584 nwam_known_wlan_handle_t kwh; 585 nwam_value_t keynameval = NULL, keyslotval = NULL, bssidsval = NULL; 586 nwam_value_t secmodeval = NULL, priorityval = NULL; 587 char **old_bssids = NULL, **new_bssids; 588 uint_t nelem = 0; 589 nwam_error_t err; 590 int i, j; 591 592 /* 593 * Check if the given ESSID already exists as known WLAN. If so, 594 * add the BSSID to the bssids property. If not, create one with 595 * the given ESSID and add BSSID if given. 596 */ 597 err = nwam_known_wlan_read(essid, 0, &kwh); 598 599 switch (err) { 600 case NWAM_ENTITY_NOT_FOUND: 601 if ((err = nwam_known_wlan_create(essid, &kwh)) != NWAM_SUCCESS) 602 return (err); 603 /* New known WLAN - set priority to 0 */ 604 if ((err = nwam_value_create_uint64(0, &priorityval)) 605 != NWAM_SUCCESS) { 606 nwam_known_wlan_free(kwh); 607 return (err); 608 } 609 err = nwam_known_wlan_set_prop_value(kwh, 610 NWAM_KNOWN_WLAN_PROP_PRIORITY, priorityval); 611 nwam_value_free(priorityval); 612 if (err != NWAM_SUCCESS) { 613 nwam_known_wlan_free(kwh); 614 return (err); 615 } 616 /* If BSSID is NULL, nothing more to do here. */ 617 if (bssid == NULL) 618 break; 619 if ((err = nwam_value_create_string((char *)bssid, &bssidsval)) 620 != NWAM_SUCCESS) { 621 nwam_known_wlan_free(kwh); 622 return (err); 623 } 624 /* Set the bssids property */ 625 err = nwam_known_wlan_set_prop_value(kwh, 626 NWAM_KNOWN_WLAN_PROP_BSSIDS, bssidsval); 627 nwam_value_free(bssidsval); 628 if (err != NWAM_SUCCESS) { 629 nwam_known_wlan_free(kwh); 630 return (err); 631 } 632 break; 633 case NWAM_SUCCESS: 634 /* If no bssid is specified, nothing to do */ 635 if (bssid == NULL) 636 break; 637 638 /* known WLAN exists, retrieve the existing bssids property */ 639 err = nwam_known_wlan_get_prop_value(kwh, 640 NWAM_KNOWN_WLAN_PROP_BSSIDS, &bssidsval); 641 if (err != NWAM_SUCCESS && err != NWAM_ENTITY_NOT_FOUND) { 642 nwam_known_wlan_free(kwh); 643 return (err); 644 } 645 if (err == NWAM_SUCCESS) { 646 if ((err = nwam_value_get_string_array(bssidsval, 647 &old_bssids, &nelem)) != NWAM_SUCCESS) { 648 nwam_value_free(bssidsval); 649 nwam_known_wlan_free(kwh); 650 return (err); 651 } 652 } 653 /* Create a new array to append given BSSID */ 654 new_bssids = calloc(nelem + 1, sizeof (char *)); 655 if (new_bssids == NULL) { 656 nwam_value_free(bssidsval); 657 nwam_known_wlan_free(kwh); 658 return (NWAM_NO_MEMORY); 659 } 660 661 /* 662 * Copy over existing BSSIDs to the new array. Also, check 663 * to make sure that the given BSSID doesn't already exist 664 * in the known WLAN. If so, do abort copying and return 665 * NWAM_SUCCESS. 666 */ 667 for (i = 0; i < nelem; i++) { 668 if (strcmp(old_bssids[i], bssid) == 0) { 669 /* nothing to do, so free up everything */ 670 for (j = 0; j < i; j++) 671 free(new_bssids[j]); 672 free(new_bssids); 673 nwam_value_free(bssidsval); 674 goto set_key_info; 675 } 676 new_bssids[i] = strdup(old_bssids[i]); 677 } 678 new_bssids[nelem] = strdup(bssid); 679 nwam_value_free(bssidsval); 680 681 err = nwam_value_create_string_array(new_bssids, nelem + 1, 682 &bssidsval); 683 for (i = 0; i < nelem + 1; i++) 684 free(new_bssids[i]); 685 free(new_bssids); 686 if (err != NWAM_SUCCESS) { 687 nwam_known_wlan_free(kwh); 688 return (err); 689 } 690 /* Set the bssids property */ 691 err = nwam_known_wlan_set_prop_value(kwh, 692 NWAM_KNOWN_WLAN_PROP_BSSIDS, bssidsval); 693 nwam_value_free(bssidsval); 694 if (err != NWAM_SUCCESS) { 695 nwam_known_wlan_free(kwh); 696 return (err); 697 } 698 break; 699 default: 700 return (err); 701 } 702 703 set_key_info: 704 /* Set the security mode property */ 705 if ((err = nwam_value_create_uint64(secmode, &secmodeval)) 706 != NWAM_SUCCESS) { 707 nwam_known_wlan_free(kwh); 708 return (err); 709 } 710 err = nwam_known_wlan_set_prop_value(kwh, 711 NWAM_KNOWN_WLAN_PROP_SECURITY_MODE, secmodeval); 712 nwam_value_free(secmodeval); 713 714 if (err != NWAM_SUCCESS) { 715 nwam_known_wlan_free(kwh); 716 return (err); 717 } 718 719 if (keyname != NULL) { 720 if ((err = nwam_value_create_string((char *)keyname, 721 &keynameval)) != NWAM_SUCCESS) { 722 nwam_known_wlan_free(kwh); 723 return (err); 724 } 725 err = nwam_known_wlan_set_prop_value(kwh, 726 NWAM_KNOWN_WLAN_PROP_KEYNAME, keynameval); 727 nwam_value_free(keynameval); 728 if (err != NWAM_SUCCESS) { 729 nwam_known_wlan_free(kwh); 730 return (err); 731 } 732 if ((err = nwam_value_create_uint64(keyslot, 733 &keyslotval)) != NWAM_SUCCESS) { 734 nwam_known_wlan_free(kwh); 735 return (err); 736 } 737 err = nwam_known_wlan_set_prop_value(kwh, 738 NWAM_KNOWN_WLAN_PROP_KEYSLOT, keyslotval); 739 nwam_value_free(keyslotval); 740 } 741 742 err = nwam_known_wlan_commit(kwh, 0); 743 nwam_known_wlan_free(kwh); 744 745 return (err); 746 } 747 748 /* 749 * Remove the given BSSID/keyname from the bssids/keyname property for the 750 * given ESSID. 751 */ 752 nwam_error_t 753 nwam_known_wlan_remove_from_known_wlans(const char *essid, const char *bssid, 754 const char *keyname) 755 { 756 nwam_known_wlan_handle_t kwh; 757 nwam_value_t bssidsval; 758 char **old_bssids, **new_bssids; 759 uint_t nelem; 760 nwam_error_t err; 761 int i, found = -1; 762 763 /* Retrieve the existing bssids */ 764 if ((err = nwam_known_wlan_read(essid, 0, &kwh)) != NWAM_SUCCESS) 765 return (err); 766 if ((err = nwam_known_wlan_get_prop_value(kwh, 767 NWAM_KNOWN_WLAN_PROP_BSSIDS, &bssidsval)) != NWAM_SUCCESS) { 768 nwam_known_wlan_free(kwh); 769 return (err); 770 } 771 if ((err = nwam_value_get_string_array(bssidsval, &old_bssids, &nelem)) 772 != NWAM_SUCCESS) { 773 nwam_value_free(bssidsval); 774 nwam_known_wlan_free(kwh); 775 return (err); 776 } 777 778 /* Cycle through the BSSIDs array to find the BSSID to remove */ 779 for (i = 0; i < nelem; i++) { 780 if (strcmp(old_bssids[i], bssid) == 0) { 781 found = i; 782 break; 783 } 784 } 785 786 /* Given BSSID was not found in the array */ 787 if (found == -1) { 788 nwam_value_free(bssidsval); 789 nwam_known_wlan_free(kwh); 790 return (NWAM_INVALID_ARG); 791 } 792 793 /* If removing the only BSSID entry, remove the bssids property */ 794 if (nelem == 1) { 795 nwam_value_free(bssidsval); 796 if ((err = nwam_known_wlan_delete_prop(kwh, 797 NWAM_KNOWN_WLAN_PROP_BSSIDS)) != NWAM_SUCCESS) { 798 nwam_known_wlan_free(kwh); 799 return (err); 800 } 801 err = nwam_known_wlan_commit(kwh, 0); 802 nwam_known_wlan_free(kwh); 803 return (err); 804 } 805 806 new_bssids = calloc(nelem - 1, sizeof (char *)); 807 if (new_bssids == NULL) { 808 nwam_value_free(bssidsval); 809 nwam_known_wlan_free(kwh); 810 return (NWAM_NO_MEMORY); 811 } 812 813 /* Copy over other BSSIDs */ 814 for (i = 0; i < found; i++) 815 new_bssids[i] = strdup(old_bssids[i]); 816 for (i = found + 1; i < nelem; i++) 817 new_bssids[i-1] = strdup(old_bssids[i]); 818 nwam_value_free(bssidsval); 819 820 err = nwam_value_create_string_array(new_bssids, nelem - 1, &bssidsval); 821 for (i = 0; i < nelem - 1; i++) 822 free(new_bssids[i]); 823 free(new_bssids); 824 if (err != NWAM_SUCCESS) { 825 nwam_known_wlan_free(kwh); 826 return (err); 827 } 828 829 /* Set the bssids property */ 830 err = nwam_known_wlan_set_prop_value(kwh, NWAM_KNOWN_WLAN_PROP_BSSIDS, 831 bssidsval); 832 nwam_value_free(bssidsval); 833 if (err != NWAM_SUCCESS) { 834 nwam_known_wlan_free(kwh); 835 return (err); 836 } 837 838 if (keyname != NULL) { 839 if ((err = nwam_known_wlan_delete_prop(kwh, 840 NWAM_KNOWN_WLAN_PROP_KEYNAME)) != NWAM_SUCCESS) { 841 nwam_known_wlan_free(kwh); 842 return (err); 843 } 844 if ((err = nwam_known_wlan_delete_prop(kwh, 845 NWAM_KNOWN_WLAN_PROP_KEYSLOT)) != NWAM_SUCCESS) { 846 nwam_known_wlan_free(kwh); 847 return (err); 848 } 849 } 850 851 err = nwam_known_wlan_commit(kwh, 0); 852 nwam_known_wlan_free(kwh); 853 854 return (err); 855 } 856