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
nwam_known_wlan_read(const char * name,uint64_t flags,nwam_known_wlan_handle_t * kwhp)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
nwam_known_wlan_create(const char * name,nwam_known_wlan_handle_t * kwhp)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
nwam_known_wlan_get_name(nwam_known_wlan_handle_t kwh,char ** namep)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
nwam_known_wlan_set_name(nwam_known_wlan_handle_t kwh,const char * name)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
nwam_known_wlan_can_set_name(nwam_known_wlan_handle_t kwh)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
get_wlans_cb(nwam_known_wlan_handle_t kwh,void * data)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
nwam_walk_known_wlans(int (* cb)(nwam_known_wlan_handle_t,void *),void * data,uint64_t flags,int * retp)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
nwam_known_wlan_free(nwam_known_wlan_handle_t kwh)283 nwam_known_wlan_free(nwam_known_wlan_handle_t kwh)
284 {
285 nwam_free(kwh);
286 }
287
288 nwam_error_t
nwam_known_wlan_copy(nwam_known_wlan_handle_t oldkwh,const char * newname,nwam_known_wlan_handle_t * newkwhp)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
nwam_known_wlan_delete_prop(nwam_known_wlan_handle_t kwh,const char * propname)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
nwam_known_wlan_set_prop_value(nwam_known_wlan_handle_t kwh,const char * propname,nwam_value_t value)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
nwam_known_wlan_get_prop_value(nwam_known_wlan_handle_t kwh,const char * propname,nwam_value_t * valuep)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
nwam_known_wlan_walk_props(nwam_known_wlan_handle_t kwh,int (* cb)(const char *,nwam_value_t,void *),void * data,uint64_t flags,int * retp)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
avoid_priority_collisions_cb(nwam_known_wlan_handle_t kwh,void * data)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
nwam_known_wlan_commit(nwam_known_wlan_handle_t kwh,uint64_t flags)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
nwam_known_wlan_destroy(nwam_known_wlan_handle_t kwh,uint64_t flags)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
nwam_known_wlan_get_prop_description(const char * propname,const char ** descriptionp)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
valid_keyname(nwam_value_t value)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
valid_keyslot(nwam_value_t value)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
valid_secmode(nwam_value_t value)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
nwam_known_wlan_validate(nwam_known_wlan_handle_t kwh,const char ** errpropp)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
nwam_known_wlan_validate_prop(nwam_known_wlan_handle_t kwh,const char * propname,nwam_value_t value)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
nwam_known_wlan_get_prop_type(const char * propname,nwam_value_type_t * typep)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
nwam_known_wlan_prop_multivalued(const char * propname,boolean_t * multip)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
nwam_known_wlan_get_default_proplist(const char *** prop_list,uint_t * numvaluesp)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
nwam_known_wlan_add_to_known_wlans(const char * essid,const char * bssid,uint32_t secmode,uint_t keyslot,const char * keyname)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
nwam_known_wlan_remove_from_known_wlans(const char * essid,const char * bssid,const char * keyname)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