dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / lib / nwamd / objects.c
blob501bfa607745c7adac704d2accb1416b770c7477
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <assert.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <pthread.h>
31 #include <signal.h>
32 #include <errno.h>
33 #include <syslog.h>
34 #include <libuutil.h>
35 #include <errno.h>
37 #include "events.h"
38 #include "objects.h"
39 #include "util.h"
42 * objects.c - contains routines which manipulate object lists of NCUs,
43 * locations, ENMs and known WLANs.
46 typedef struct nwamd_object_list {
47 nwam_object_type_t object_type;
48 uu_list_t *object_list;
49 nwamd_event_method_t *object_event_methods;
50 pthread_rwlock_t object_list_lock;
51 } nwamd_object_list_t;
53 nwamd_event_method_t enm_event_methods[] =
55 { NWAM_EVENT_TYPE_OBJECT_INIT, nwamd_enm_handle_init_event },
56 { NWAM_EVENT_TYPE_OBJECT_FINI, nwamd_enm_handle_fini_event },
57 { NWAM_EVENT_TYPE_OBJECT_ACTION, nwamd_enm_handle_action_event },
58 { NWAM_EVENT_TYPE_OBJECT_STATE, nwamd_enm_handle_state_event },
59 { NWAM_EVENT_TYPE_NOOP, NULL }
62 nwamd_event_method_t loc_event_methods[] =
64 { NWAM_EVENT_TYPE_OBJECT_INIT, nwamd_loc_handle_init_event },
65 { NWAM_EVENT_TYPE_OBJECT_FINI, nwamd_loc_handle_fini_event },
66 { NWAM_EVENT_TYPE_OBJECT_ACTION, nwamd_loc_handle_action_event },
67 { NWAM_EVENT_TYPE_OBJECT_STATE, nwamd_loc_handle_state_event },
68 { NWAM_EVENT_TYPE_NOOP, NULL }
71 nwamd_event_method_t ncu_event_methods[] =
73 { NWAM_EVENT_TYPE_IF_STATE, nwamd_ncu_handle_if_state_event },
74 { NWAM_EVENT_TYPE_IF_ACTION, nwamd_ncu_handle_if_action_event },
75 { NWAM_EVENT_TYPE_LINK_STATE, nwamd_ncu_handle_link_state_event },
76 { NWAM_EVENT_TYPE_LINK_ACTION, nwamd_ncu_handle_link_action_event },
77 { NWAM_EVENT_TYPE_OBJECT_INIT, nwamd_ncu_handle_init_event },
78 { NWAM_EVENT_TYPE_OBJECT_FINI, nwamd_ncu_handle_fini_event },
79 { NWAM_EVENT_TYPE_OBJECT_ACTION, nwamd_ncu_handle_action_event },
80 { NWAM_EVENT_TYPE_OBJECT_STATE, nwamd_ncu_handle_state_event },
81 { NWAM_EVENT_TYPE_PERIODIC_SCAN, nwamd_ncu_handle_periodic_scan_event },
82 { NWAM_EVENT_TYPE_NOOP, NULL }
85 nwamd_event_method_t ncp_event_methods[] =
87 { NWAM_EVENT_TYPE_OBJECT_ACTION, nwamd_ncp_handle_action_event },
88 { NWAM_EVENT_TYPE_OBJECT_STATE, nwamd_ncp_handle_state_event },
89 { NWAM_EVENT_TYPE_UPGRADE, nwamd_handle_upgrade },
90 { NWAM_EVENT_TYPE_NOOP, NULL }
93 nwamd_event_method_t known_wlan_event_methods[] =
95 { NWAM_EVENT_TYPE_OBJECT_INIT, nwamd_known_wlan_handle_init_event },
96 { NWAM_EVENT_TYPE_OBJECT_FINI, NULL },
97 { NWAM_EVENT_TYPE_OBJECT_ACTION, nwamd_known_wlan_handle_action_event },
98 { NWAM_EVENT_TYPE_NOOP, NULL }
101 /* Should be kept in same order as object types */
102 nwamd_object_list_t object_lists[] = {
103 { NWAM_OBJECT_TYPE_NCP, NULL, ncp_event_methods,
104 PTHREAD_RWLOCK_INITIALIZER },
105 { NWAM_OBJECT_TYPE_NCU, NULL, ncu_event_methods,
106 PTHREAD_RWLOCK_INITIALIZER },
107 { NWAM_OBJECT_TYPE_LOC, NULL, loc_event_methods,
108 PTHREAD_RWLOCK_INITIALIZER },
109 { NWAM_OBJECT_TYPE_ENM, NULL, enm_event_methods,
110 PTHREAD_RWLOCK_INITIALIZER },
111 { NWAM_OBJECT_TYPE_KNOWN_WLAN, NULL, known_wlan_event_methods,
112 PTHREAD_RWLOCK_INITIALIZER }
115 uu_list_pool_t *object_list_pool = NULL;
118 * Comparison function for objects, passed in as callback to
119 * uu_list_pool_create().
121 /* ARGSUSED */
122 static int
123 nwamd_object_compare(const void *l_arg, const void *r_arg, void *private)
125 nwamd_object_t l = (nwamd_object_t)l_arg;
126 nwamd_object_t r = (nwamd_object_t)r_arg;
127 int rv;
129 (void) pthread_mutex_lock(&l->nwamd_object_mutex);
130 if (l != r)
131 (void) pthread_mutex_lock(&r->nwamd_object_mutex);
133 rv = strcmp(l->nwamd_object_name, r->nwamd_object_name);
134 if (l != r)
135 (void) pthread_mutex_unlock(&r->nwamd_object_mutex);
136 (void) pthread_mutex_unlock(&l->nwamd_object_mutex);
138 return (rv);
141 void
142 nwamd_object_lists_init(void)
144 int i;
146 object_list_pool = uu_list_pool_create("object_list_pool",
147 sizeof (struct nwamd_object),
148 offsetof(struct nwamd_object, nwamd_object_node),
149 nwamd_object_compare, UU_LIST_POOL_DEBUG);
150 if (object_list_pool == NULL)
151 pfail("uu_list_pool_create failed with error %d", uu_error());
153 for (i = 0;
154 i < sizeof (object_lists) / sizeof (struct nwamd_object_list);
155 i++) {
156 object_lists[i].object_list = uu_list_create(object_list_pool,
157 NULL, 0);
158 if (object_lists[i].object_list == NULL)
159 pfail("uu_list_create failed with error %d",
160 uu_error());
164 void
165 nwamd_object_lists_fini(void)
167 int i;
168 nwamd_object_t object;
169 void *cookie = NULL;
171 for (i = 0;
172 i < sizeof (object_lists) / sizeof (struct nwamd_object_list);
173 i++) {
174 while ((object = uu_list_teardown(object_lists[i].object_list,
175 &cookie)) != NULL) {
176 free(object);
178 uu_list_destroy(object_lists[i].object_list);
180 if (object_list_pool != NULL)
181 uu_list_pool_destroy(object_list_pool);
184 static nwamd_object_list_t *
185 nwamd_get_object_list(nwam_object_type_t type)
187 assert(type < sizeof (object_lists) / sizeof (object_lists[0]));
188 return (&object_lists[type]);
191 static int
192 nwamd_object_list_lock(nwam_object_type_t type)
194 nwamd_object_list_t *object_list = nwamd_get_object_list(type);
196 (void) pthread_rwlock_wrlock(&object_list->object_list_lock);
197 return (0);
200 static int
201 nwamd_object_list_rlock(nwam_object_type_t type)
203 nwamd_object_list_t *object_list = nwamd_get_object_list(type);
205 if (pthread_rwlock_rdlock(&object_list->object_list_lock) == -1) {
206 nlog(LOG_ERR, "cannot get lock for object list: %s",
207 strerror(errno));
208 return (-1);
210 return (0);
213 static void
214 nwamd_object_list_unlock(nwam_object_type_t type)
216 nwamd_object_list_t *object_list = nwamd_get_object_list(type);
218 (void) pthread_rwlock_unlock(&object_list->object_list_lock);
222 * Initialize object and return it in locked state.
224 nwamd_object_t
225 nwamd_object_init(nwam_object_type_t type, const char *name, void *handle,
226 void *data)
228 nwamd_object_t object;
229 struct nwamd_object_list *object_list = nwamd_get_object_list(type);
231 object = calloc(1, sizeof (struct nwamd_object));
232 if (object == NULL)
233 return (NULL);
235 (void) strlcpy(object->nwamd_object_name, name, NWAM_MAX_NAME_LEN);
237 /* 1 for the list and 1 for the returned object */
238 object->nwamd_object_refcount = 2;
239 object->nwamd_object_handle = handle;
240 object->nwamd_object_data = data;
241 object->nwamd_object_type = type;
242 object->nwamd_object_state = NWAM_STATE_INITIALIZED;
243 object->nwamd_object_aux_state = NWAM_AUX_STATE_INITIALIZED;
245 /* Add object to appropriate object list */
246 if (nwamd_object_list_lock(type) != 0) {
247 nlog(LOG_ERR, "nwamd_object_init: could not lock list to init "
248 "object %s", name);
249 free(object);
250 return (NULL);
253 if (pthread_mutex_init(&object->nwamd_object_mutex, NULL) == -1) {
254 nlog(LOG_ERR, "pthread_mutex_init failed: %s",
255 strerror(errno));
256 free(object);
257 nwamd_object_list_unlock(type);
258 return (NULL);
260 (void) pthread_mutex_lock(&object->nwamd_object_mutex);
262 uu_list_node_init(object, &object->nwamd_object_node, object_list_pool);
263 (void) uu_list_insert_after(object_list->object_list,
264 uu_list_last(object_list->object_list), object);
266 nwamd_object_list_unlock(type);
268 return (object);
272 * Find object in object list, returning it holding a lock and with the
273 * reference count incremented. The opposite function to this is
274 * nwamd_object_release().
276 nwamd_object_t
277 nwamd_object_find(nwam_object_type_t type, const char *name)
279 nwamd_object_t object;
280 struct nwamd_object_list *object_list = nwamd_get_object_list(type);
282 assert(name != NULL);
284 if (nwamd_object_list_rlock(type) != 0)
285 return (NULL);
287 for (object = uu_list_first(object_list->object_list);
288 object != NULL;
289 object = uu_list_next(object_list->object_list, object)) {
290 if (strcmp(object->nwamd_object_name, name) == 0)
291 break;
293 if (object != NULL) {
294 (void) pthread_mutex_lock(&object->nwamd_object_mutex);
295 object->nwamd_object_refcount++;
297 nwamd_object_list_unlock(type);
299 return (object);
302 /* Removes object from list, destroy mutex, and free storage. */
303 static void
304 nwamd_object_fini(nwamd_object_t object, nwam_object_type_t objtype)
306 nwamd_object_t o;
307 struct nwamd_object_list *object_list;
309 assert(object != NULL);
311 object_list = nwamd_get_object_list(objtype);
313 for (o = uu_list_first(object_list->object_list);
314 o != NULL;
315 o = uu_list_next(object_list->object_list, o)) {
316 if (o == object) {
317 uu_list_remove(object_list->object_list, object);
318 (void) pthread_mutex_unlock(
319 &object->nwamd_object_mutex);
320 (void) pthread_mutex_destroy(
321 &object->nwamd_object_mutex);
322 uu_list_node_fini(object, &object->nwamd_object_node,
323 object_list_pool);
324 switch (objtype) {
325 case NWAM_OBJECT_TYPE_NCU:
326 nwamd_ncu_free(object->nwamd_object_data);
327 nwam_ncu_free(object->nwamd_object_handle);
328 break;
329 case NWAM_OBJECT_TYPE_LOC:
330 nwam_loc_free(object->nwamd_object_handle);
331 break;
332 case NWAM_OBJECT_TYPE_ENM:
333 nwam_enm_free(object->nwamd_object_handle);
334 break;
335 default:
336 nlog(LOG_ERR, "nwamd_object_fini: "
337 "got unexpected object type %d", objtype);
338 break;
340 free(object);
341 break;
346 static void
347 nwamd_object_decref(nwamd_object_t object, int num)
349 nwam_object_type_t objtype;
351 assert(object->nwamd_object_refcount >= num);
352 object->nwamd_object_refcount -= num;
353 if (object->nwamd_object_refcount == 0) {
355 * We need to maintain the locking hierarchy of owning the
356 * list lock before we get the object lock when we are
357 * destroying the object. If we merely release and then
358 * reacquire in the right order we might not find the right
359 * object. Instead we bump the ref count so that it can't
360 * be destroyed, we drop the object lock, we acquire the
361 * list lock, we acquire the object lock, decrement the ref
362 * count, check to make sure we are really destroying it and
363 * somebody else hasn't gotten it, and then, if its unref'd,
364 * destroying it.
366 object->nwamd_object_refcount++;
367 objtype = object->nwamd_object_type;
368 (void) pthread_mutex_unlock(&object->nwamd_object_mutex);
369 (void) nwamd_object_list_lock(objtype);
370 (void) pthread_mutex_lock(&object->nwamd_object_mutex);
371 if (--object->nwamd_object_refcount != 0)
372 (void) pthread_mutex_unlock(
373 &object->nwamd_object_mutex);
374 else
375 nwamd_object_fini(object, objtype);
376 nwamd_object_list_unlock(objtype);
377 } else {
378 (void) pthread_mutex_unlock(&object->nwamd_object_mutex);
383 * Drop mutex without decreasing reference count. Used where we wish to
384 * let go of an object but ensure it will not go away.
386 void
387 nwamd_object_release_and_preserve(nwamd_object_t object)
389 (void) pthread_mutex_unlock(&object->nwamd_object_mutex);
392 void
393 nwamd_object_release(nwamd_object_t object)
395 nwamd_object_decref(object, 1);
398 void
399 nwamd_object_release_and_destroy(nwamd_object_t object)
401 nwamd_object_decref(object, 2);
404 void
405 nwamd_object_release_and_destroy_after_preserve(nwamd_object_t object)
407 nwamd_object_decref(object, 3);
410 void
411 nwamd_object_release_after_preserve(nwamd_object_t object)
413 nwamd_object_decref(object, 2);
416 void
417 nwamd_object_set_state_timed(nwam_object_type_t type, const char *name,
418 nwam_state_t state, nwam_aux_state_t aux_state, uint32_t when)
420 nwamd_event_t event = nwamd_event_init_object_state(type, name,
421 state, aux_state);
423 nlog(LOG_INFO, "nwamd_object_set_state: state event (%s, %s) for %s",
424 nwam_state_to_string(state),
425 nwam_aux_state_to_string(aux_state), name);
426 if (event != NULL)
427 nwamd_event_enqueue_timed(event, when);
430 void
431 nwamd_object_set_state(nwam_object_type_t type, const char *name,
432 nwam_state_t state, nwam_aux_state_t aux_state)
434 nwamd_object_set_state_timed(type, name, state, aux_state, 0);
437 nwamd_event_method_t *
438 nwamd_object_event_methods(nwam_object_type_t type)
440 struct nwamd_object_list *object_list = nwamd_get_object_list(type);
442 return (object_list->object_event_methods);
446 * Walk all objects of specified type calling callback function cb.
447 * Object is locked for duration of callback.
450 nwamd_walk_objects(nwam_object_type_t type, int (*cb)(nwamd_object_t, void *),
451 void *data)
453 nwamd_object_t object;
454 struct nwamd_object_list *object_list = nwamd_get_object_list(type);
455 int ret = 0;
457 if (nwamd_object_list_rlock(type) != 0)
458 return (-1);
460 for (object = uu_list_first(object_list->object_list);
461 object != NULL;
462 object = uu_list_next(object_list->object_list, object)) {
463 (void) pthread_mutex_lock(&object->nwamd_object_mutex);
464 ret = cb(object, data);
465 (void) pthread_mutex_unlock(&object->nwamd_object_mutex);
466 if (ret != 0) {
467 nwamd_object_list_unlock(type);
468 return (ret);
471 nwamd_object_list_unlock(type);
473 return (0);