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]
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <arpa/inet.h>
31 #include <libdllink.h>
32 #include <libdlwlan.h>
39 #include "conditions.h"
45 * conditions.c - contains routines which check state to see if activation
46 * conditions for NWAM objects are satisfied and rates activation conditions to
47 * help determine which is most specific.
49 * If the activation-mode is CONDITIONAL_ANY or CONDITIONAL_ALL, the conditions
50 * property is set to a string made up of conditional expressions. Each
51 * expression is made up of a condition that can be assigned a boolean value,
52 * e.g. "system-domain is sun.com" or "ncu ip:bge0 is-not active". If the
53 * activation-mode is CONDITIONAL_ANY, the condition will be satisfied if any
54 * one of the conditions is true; if the activation-mode is CONDITIONAL_ALL,
55 * the condition is satisfied only if all of the conditions are true.
58 uint64_t condition_check_interval
= CONDITION_CHECK_INTERVAL_DEFAULT
;
60 extern int getdomainname(char *, int);
62 /* NCP, NCU, ENM and location conditions */
63 static boolean_t
test_condition_ncp(nwam_condition_t condition
,
64 const char *ncp_name
);
65 static boolean_t
test_condition_ncu(nwam_condition_t condition
,
66 const char *ncu_name
);
67 static boolean_t
test_condition_enm(nwam_condition_t condition
,
68 const char *enm_name
);
69 static boolean_t
test_condition_loc(nwam_condition_t condition
,
70 const char *loc_name
);
72 /* IP address conditions */
73 static boolean_t
test_condition_ip_address(nwam_condition_t condition
,
74 const char *ip_address
);
76 /* domainname conditions */
77 static boolean_t
test_condition_sys_domain(nwam_condition_t condition
,
78 const char *domainname
);
79 static boolean_t
test_condition_adv_domain(nwam_condition_t condition
,
80 const char *domainname
);
83 static boolean_t
test_condition_wireless_essid(nwam_condition_t condition
,
85 static boolean_t
test_condition_wireless_bssid(nwam_condition_t condition
,
88 struct nwamd_condition_map
{
89 nwam_condition_object_type_t object_type
;
90 boolean_t (*condition_func
)(nwam_condition_t
, const char *);
93 { NWAM_CONDITION_OBJECT_TYPE_NCP
, test_condition_ncp
},
94 { NWAM_CONDITION_OBJECT_TYPE_NCU
, test_condition_ncu
},
95 { NWAM_CONDITION_OBJECT_TYPE_ENM
, test_condition_enm
},
96 { NWAM_CONDITION_OBJECT_TYPE_LOC
, test_condition_loc
},
97 { NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS
, test_condition_ip_address
},
98 { NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN
, test_condition_sys_domain
},
99 { NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN
, test_condition_adv_domain
},
100 { NWAM_CONDITION_OBJECT_TYPE_ESSID
, test_condition_wireless_essid
},
101 { NWAM_CONDITION_OBJECT_TYPE_BSSID
, test_condition_wireless_bssid
}
105 * This function takes which kind of conditions (is or is not) we are testing
106 * the object against and an object and applies the conditon to the object.
109 test_condition_object_state(nwam_condition_t condition
,
110 nwam_object_type_t object_type
, const char *object_name
)
112 nwamd_object_t object
;
115 object
= nwamd_object_find(object_type
, object_name
);
119 state
= object
->nwamd_object_state
;
120 nwamd_object_release(object
);
123 case NWAM_CONDITION_IS
:
124 return (state
== NWAM_STATE_ONLINE
);
125 case NWAM_CONDITION_IS_NOT
:
126 return (state
!= NWAM_STATE_ONLINE
);
133 test_condition_ncp(nwam_condition_t condition
, const char *name
)
137 (void) pthread_mutex_lock(&active_ncp_mutex
);
138 active
= (strcasecmp(active_ncp
, name
) == 0);
139 (void) pthread_mutex_unlock(&active_ncp_mutex
);
142 case NWAM_CONDITION_IS
:
144 case NWAM_CONDITION_IS_NOT
:
145 return (active
!= B_TRUE
);
152 test_condition_ncu(nwam_condition_t condition
, const char *name
)
154 char *real_name
, *ncu_name
;
155 nwam_ncu_handle_t ncuh
;
156 nwam_ncu_type_t ncu_type
;
159 /* names are case-insensitive, so get real name from libnwam */
160 if (nwam_ncu_read(active_ncph
, name
, NWAM_NCU_TYPE_INTERFACE
, 0, &ncuh
)
162 ncu_type
= NWAM_NCU_TYPE_INTERFACE
;
163 } else if (nwam_ncu_read(active_ncph
, name
, NWAM_NCU_TYPE_LINK
, 0,
164 &ncuh
) == NWAM_SUCCESS
) {
165 ncu_type
= NWAM_NCU_TYPE_LINK
;
169 if (nwam_ncu_get_name(ncuh
, &real_name
) != NWAM_SUCCESS
) {
176 * Name may be either unqualified or qualified by NCU type
177 * (interface:/link:). Need to translate unqualified names
178 * to qualified, specifying interface:name if an interface
179 * NCU is present, otherwise link:ncu.
181 if (nwam_ncu_name_to_typed_name(real_name
, ncu_type
, &ncu_name
)
188 rv
= test_condition_object_state(condition
, NWAM_OBJECT_TYPE_NCU
,
195 test_condition_enm(nwam_condition_t condition
, const char *enm_name
)
197 nwam_enm_handle_t enmh
;
201 /* names are case-insensitive, so get real name from libnwam */
202 if (nwam_enm_read(enm_name
, 0, &enmh
) != NWAM_SUCCESS
)
204 if (nwam_enm_get_name(enmh
, &real_name
) != NWAM_SUCCESS
) {
210 rv
= test_condition_object_state(condition
, NWAM_OBJECT_TYPE_ENM
,
217 test_condition_loc(nwam_condition_t condition
, const char *loc_name
)
219 nwam_loc_handle_t loch
;
223 /* names are case-insensitive, so get real name from libnwam */
224 if (nwam_loc_read(loc_name
, 0, &loch
) != NWAM_SUCCESS
)
226 if (nwam_loc_get_name(loch
, &real_name
) != NWAM_SUCCESS
) {
232 rv
= test_condition_object_state(condition
, NWAM_OBJECT_TYPE_LOC
,
239 test_condition_domain(nwam_condition_t condition
, const char *target_domain
,
240 const char *found_domain
)
243 char target
[MAXHOSTNAMELEN
], found
[MAXHOSTNAMELEN
];
245 len_t
= target_domain
== NULL
? 0 : strlen(target_domain
);
246 len_f
= found_domain
== NULL
? 0 : strlen(found_domain
);
248 /* convert target_domain and found_domain to lowercase for strstr() */
249 for (i
= 0; i
< len_t
; i
++)
250 target
[i
] = tolower(target_domain
[i
]);
251 target
[len_t
] = '\0';
253 for (i
= 0; i
< len_f
; i
++)
254 found
[i
] = tolower(found_domain
[i
]);
258 case NWAM_CONDITION_IS
:
259 return (found_domain
!= NULL
&& strcmp(found
, target
) == 0);
260 case NWAM_CONDITION_IS_NOT
:
261 return (found_domain
== NULL
|| strcmp(found
, target
) != 0);
262 case NWAM_CONDITION_CONTAINS
:
263 return (found_domain
!= NULL
&& strstr(found
, target
) != NULL
);
264 case NWAM_CONDITION_DOES_NOT_CONTAIN
:
265 return (found_domain
== NULL
|| strstr(found
, target
) == NULL
);
271 struct ncu_adv_domains
{
272 struct ncu_adv_domains
*next
;
278 get_adv_domains(nwamd_object_t obj
, void *arg
)
280 nwamd_ncu_t
*ncu
= (nwamd_ncu_t
*)obj
->nwamd_object_data
;
281 struct ncu_adv_domains
**headpp
= (struct ncu_adv_domains
**)arg
;
282 struct ncu_adv_domains
*adp
;
285 if (ncu
->ncu_type
!= NWAM_NCU_TYPE_INTERFACE
)
288 dns
= nwamd_get_dhcpinfo_data("DNSdmain", ncu
->ncu_name
);
289 nis
= nwamd_get_dhcpinfo_data("NISdmain", ncu
->ncu_name
);
291 if (dns
!= NULL
|| nis
!= NULL
) {
292 adp
= (struct ncu_adv_domains
*)malloc(sizeof (*adp
));
295 adp
->dns_domain
= dns
;
296 adp
->nis_domain
= nis
;
305 test_condition_sys_domain(nwam_condition_t condition
, const char *domainname
)
307 char cur_domainname
[MAXHOSTNAMELEN
];
309 if (getdomainname(cur_domainname
, MAXHOSTNAMELEN
) != 0)
312 return (test_condition_domain(condition
, domainname
, cur_domainname
));
316 test_condition_adv_domain(nwam_condition_t condition
, const char *domainname
)
318 struct ncu_adv_domains
*adv_domains
= NULL
;
319 struct ncu_adv_domains
*adp
, *prev
;
320 boolean_t positive
, rtn
;
322 (void) nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU
, get_adv_domains
,
325 positive
= (condition
== NWAM_CONDITION_IS
||
326 condition
== NWAM_CONDITION_CONTAINS
);
329 * Walk the advertised domain list. Our test function tests one
330 * single domain, but we're dealing with a list: if our condition
331 * is positive ('is' or 'contains'), the test function for each
332 * domain results are or'd together; if our condition is negative
333 * ('is-not' or 'does-not-contain'), the test function results must
334 * be and'd. Thus our short-circuit exit value depends on our
335 * condition: if the test function returns TRUE it implies immediate
336 * success for a positive condition; if it returns FALSE it implies
337 * immediate failure for a negative condition.
340 while (adp
!= NULL
) {
341 if ((test_condition_domain(condition
, domainname
,
342 adp
->dns_domain
) == positive
) ||
343 (test_condition_domain(condition
, domainname
,
344 adp
->nis_domain
) == positive
)) {
352 * We did not short-circuit; we therefore failed if our
353 * condition was positive, and succeeded if our condition
359 /* now free the domain list */
361 while (adp
!= NULL
) {
364 free(prev
->dns_domain
);
365 free(prev
->nis_domain
);
373 * Returns true if prefixlen bits of addr1 match prefixlen bits of addr2.
376 prefixmatch(uchar_t
*addr1
, uchar_t
*addr2
, int prefixlen
)
378 uchar_t mask
[IPV6_ABITS
/8];
384 while (prefixlen
> 0) {
385 if (prefixlen
>= 8) {
389 mask
[j
] |= 1 << (8 - prefixlen
);
393 /* Ensure at least one byte is tested */
396 for (i
= 0; i
< j
; i
++) {
397 if ((addr1
[i
] & mask
[i
]) != (addr2
[i
] & mask
[i
]))
404 * Given a string representation of an IPv4 or IPv6 address returns the
405 * sockaddr representation. Note that 'sockaddr' should point at the correct
406 * sockaddr structure for the address family (sockaddr_in for AF_INET or
407 * sockaddr_in6 for AF_INET6) or alternatively at a sockaddr_storage
410 static struct sockaddr_storage
*
411 nwamd_str2sockaddr(sa_family_t af
, const char *straddr
,
412 struct sockaddr_storage
*addr
)
414 struct sockaddr_in
*sin
;
415 struct sockaddr_in6
*sin6
;
419 sin
= (struct sockaddr_in
*)addr
;
420 sin
->sin_family
= AF_INET
;
421 err
= inet_pton(AF_INET
, straddr
, &sin
->sin_addr
);
422 } else if (af
== AF_INET6
) {
423 sin6
= (struct sockaddr_in6
*)addr
;
424 sin6
->sin6_family
= AF_INET6
;
425 err
= inet_pton(AF_INET6
, straddr
, &sin6
->sin6_addr
);
430 return (err
== 1 ? addr
: NULL
);
433 struct nwamd_ipaddr_condition_walk_arg
{
434 nwam_condition_t condition
;
435 struct sockaddr_storage sockaddr
;
441 check_ipaddr(sa_family_t family
, struct ifaddrs
*ifa
, void *arg
)
443 struct nwamd_ipaddr_condition_walk_arg
*wa
= arg
;
444 struct sockaddr_in6 addr6
;
445 struct sockaddr_in addr
;
446 boolean_t match
= B_FALSE
;
447 uchar_t
*addr1
, *addr2
;
449 if (family
== AF_INET
) {
450 (void) memcpy(&addr
, ifa
->ifa_addr
, sizeof (addr
));
451 addr1
= (uchar_t
*)(&addr
.sin_addr
.s_addr
);
452 addr2
= (uchar_t
*)&(((struct sockaddr_in
*)
453 &(wa
->sockaddr
))->sin_addr
.s_addr
);
455 (void) memcpy(&addr6
, ifa
->ifa_addr
, sizeof (addr6
));
456 addr1
= (uchar_t
*)(&addr6
.sin6_addr
.s6_addr
);
457 addr2
= (uchar_t
*)&(((struct sockaddr_in6
*)
458 &(wa
->sockaddr
))->sin6_addr
.s6_addr
);
461 match
= prefixmatch(addr1
, addr2
, wa
->prefixlen
);
463 nlog(LOG_DEBUG
, "check_ipaddr: match %d\n", match
);
464 switch (wa
->condition
) {
465 case NWAM_CONDITION_IS
:
466 case NWAM_CONDITION_IS_IN_RANGE
:
471 case NWAM_CONDITION_IS_NOT
:
472 case NWAM_CONDITION_IS_NOT_IN_RANGE
:
481 test_condition_ip_address(nwam_condition_t condition
,
482 const char *ip_address_string
)
485 char *copy
, *ip_address
, *prefixlen_string
, *lasts
;
486 struct nwamd_ipaddr_condition_walk_arg wa
;
487 struct ifaddrs
*ifap
, *ifa
;
489 if ((copy
= strdup(ip_address_string
)) == NULL
)
492 if ((ip_address
= strtok_r(copy
, " \t/", &lasts
)) == NULL
) {
497 prefixlen_string
= strtok_r(NULL
, " \t", &lasts
);
499 if (nwamd_str2sockaddr(AF_INET
, ip_address
, &wa
.sockaddr
) != NULL
) {
501 wa
.prefixlen
= IP_ABITS
;
502 } else if (nwamd_str2sockaddr(AF_INET6
, ip_address
, &wa
.sockaddr
)
505 wa
.prefixlen
= IPV6_ABITS
;
507 nlog(LOG_ERR
, "test_condition_ip_address: "
508 "nwamd_str2sockaddr failed for %s: %s", ip_address
,
514 if (prefixlen_string
!= NULL
)
515 wa
.prefixlen
= atoi(prefixlen_string
);
517 wa
.condition
= condition
;
520 case NWAM_CONDITION_IS
:
521 case NWAM_CONDITION_IS_IN_RANGE
:
524 case NWAM_CONDITION_IS_NOT
:
525 case NWAM_CONDITION_IS_NOT_IN_RANGE
:
534 if (getifaddrs(&ifa
) == -1) {
535 nlog(LOG_ERR
, "test_condition_ip_address: "
536 "getifaddrs failed: %s", strerror(errno
));
539 for (ifap
= ifa
; ifap
!= NULL
; ifap
= ifap
->ifa_next
) {
540 if (ifap
->ifa_addr
->sa_family
!= family
)
542 if (check_ipaddr(family
, ifap
, &wa
) == 1)
550 struct nwamd_wlan_condition_walk_arg
{
551 nwam_condition_t condition
;
552 const char *exp_essid
;
553 const char *exp_bssid
;
554 uint_t num_connected
;
559 check_wlan(const char *linkname
, void *arg
)
561 struct nwamd_wlan_condition_walk_arg
*wa
= arg
;
562 datalink_id_t linkid
;
563 dladm_wlan_linkattr_t attr
;
564 dladm_status_t status
;
565 char cur_essid
[DLADM_STRSIZE
];
566 char cur_bssid
[DLADM_STRSIZE
];
567 char errmsg
[DLADM_STRSIZE
];
569 if ((status
= dladm_name2info(dld_handle
, linkname
, &linkid
, NULL
, NULL
,
570 NULL
)) != DLADM_STATUS_OK
) {
571 nlog(LOG_DEBUG
, "check_wlan: dladm_name2info() for %s "
572 "failed: %s", linkname
,
573 dladm_status2str(status
, errmsg
));
574 return (DLADM_WALK_CONTINUE
);
577 status
= dladm_wlan_get_linkattr(dld_handle
, linkid
, &attr
);
578 if (status
!= DLADM_STATUS_OK
) {
579 nlog(LOG_DEBUG
, "check_wlan: dladm_wlan_get_linkattr() for %s "
580 "failed: %s", linkname
,
581 dladm_status2str(status
, errmsg
));
582 return (DLADM_WALK_CONTINUE
);
584 if (attr
.la_status
== DLADM_WLAN_LINK_DISCONNECTED
)
585 return (DLADM_WALK_TERMINATE
);
589 if (wa
->exp_essid
!= NULL
) {
590 /* Is the NIC associated with the expected access point? */
591 (void) dladm_wlan_essid2str(&attr
.la_wlan_attr
.wa_essid
,
593 switch (wa
->condition
) {
594 case NWAM_CONDITION_IS
:
595 wa
->res
= strcmp(cur_essid
, wa
->exp_essid
) == 0;
597 return (DLADM_WALK_TERMINATE
);
599 case NWAM_CONDITION_IS_NOT
:
600 wa
->res
= strcmp(cur_essid
, wa
->exp_essid
) != 0;
602 return (DLADM_WALK_TERMINATE
);
604 case NWAM_CONDITION_CONTAINS
:
605 wa
->res
= strstr(cur_essid
, wa
->exp_essid
) != NULL
;
607 return (DLADM_WALK_TERMINATE
);
609 case NWAM_CONDITION_DOES_NOT_CONTAIN
:
610 wa
->res
= strstr(cur_essid
, wa
->exp_essid
) == NULL
;
612 return (DLADM_WALK_TERMINATE
);
615 return (DLADM_WALK_TERMINATE
);
617 return (DLADM_WALK_CONTINUE
);
619 if (wa
->exp_bssid
!= NULL
) {
620 /* Is the NIC associated with the expected access point? */
621 (void) dladm_wlan_bssid2str(&attr
.la_wlan_attr
.wa_bssid
,
623 switch (wa
->condition
) {
624 case NWAM_CONDITION_IS
:
625 wa
->res
= strcmp(cur_bssid
, wa
->exp_bssid
) == 0;
627 return (DLADM_WALK_TERMINATE
);
629 case NWAM_CONDITION_IS_NOT
:
630 wa
->res
= strcmp(cur_bssid
, wa
->exp_bssid
) != 0;
632 return (DLADM_WALK_TERMINATE
);
635 return (DLADM_WALK_TERMINATE
);
637 return (DLADM_WALK_CONTINUE
);
640 * Neither an ESSID or BSSID match is required - being connected to a
643 switch (wa
->condition
) {
644 case NWAM_CONDITION_IS
:
646 return (DLADM_WALK_TERMINATE
);
649 return (DLADM_WALK_TERMINATE
);
652 return (DLADM_WALK_CONTINUE
);
656 test_condition_wireless_essid(nwam_condition_t condition
,
659 struct nwamd_wlan_condition_walk_arg wa
;
661 wa
.condition
= condition
;
662 wa
.exp_essid
= essid
;
664 wa
.num_connected
= 0;
667 (void) dladm_walk(check_wlan
, dld_handle
, &wa
, DATALINK_CLASS_PHYS
,
668 DL_WIFI
, DLADM_OPT_ACTIVE
);
670 return (wa
.num_connected
> 0 && wa
.res
== B_TRUE
);
674 test_condition_wireless_bssid(nwam_condition_t condition
,
677 struct nwamd_wlan_condition_walk_arg wa
;
679 wa
.condition
= condition
;
680 wa
.exp_bssid
= bssid
;
682 wa
.num_connected
= 0;
685 (void) dladm_walk(check_wlan
, dld_handle
, &wa
, DATALINK_CLASS_PHYS
,
686 DL_WIFI
, DLADM_OPT_ACTIVE
);
688 return (wa
.num_connected
> 0 && wa
.res
== B_TRUE
);
692 * This function takes an activation mode and a string representation of a
693 * condition and evaluates it.
696 nwamd_check_conditions(nwam_activation_mode_t activation_mode
,
697 char **condition_strings
, uint_t num_conditions
)
700 nwam_condition_t condition
;
701 nwam_condition_object_type_t object_type
;
705 for (i
= 0; i
< num_conditions
; i
++) {
707 if (nwam_condition_string_to_condition(condition_strings
[i
],
708 &object_type
, &condition
, &object_name
) != NWAM_SUCCESS
) {
709 nlog(LOG_ERR
, "check_conditions: invalid condition %s",
710 condition_strings
[i
]);
715 for (j
= 0; j
< (sizeof (condition_map
) /
716 sizeof (struct nwamd_condition_map
)); j
++) {
717 if (condition_map
[j
].object_type
== object_type
)
718 ret
= condition_map
[j
].condition_func(condition
,
724 if (activation_mode
== NWAM_ACTIVATION_MODE_CONDITIONAL_ANY
&&
728 if (activation_mode
== NWAM_ACTIVATION_MODE_CONDITIONAL_ALL
&&
733 if (activation_mode
== NWAM_ACTIVATION_MODE_CONDITIONAL_ANY
&& ret
)
735 if (activation_mode
== NWAM_ACTIVATION_MODE_CONDITIONAL_ALL
&& ret
)
742 * In rating activation conditions, we take the best-rated CONDITIONAL_ANY
743 * condition, or sum all the CONDITIONAL_ALL condition ratings. This allows
744 * us to compare between location activation conditions to pick the best.
747 nwamd_rate_conditions(nwam_activation_mode_t activation_mode
,
748 char **conditions
, uint_t num_conditions
)
750 nwam_condition_t condition
;
751 nwam_condition_object_type_t object_type
;
754 uint64_t rating
= 0, total_rating
= 0;
756 for (i
= 0; i
< num_conditions
; i
++) {
759 if (nwam_condition_string_to_condition(conditions
[i
],
760 &object_type
, &condition
, &object_name
) != NWAM_SUCCESS
||
761 nwam_condition_rate(object_type
, condition
, &rating
)
763 nlog(LOG_ERR
, "nwamd_rate_conditions: could not rate "
770 if (activation_mode
== NWAM_ACTIVATION_MODE_CONDITIONAL_ANY
) {
771 if (rating
> total_rating
)
772 total_rating
= rating
;
773 } else if (activation_mode
==
774 NWAM_ACTIVATION_MODE_CONDITIONAL_ALL
) {
775 total_rating
+= rating
;
778 return (total_rating
);
782 * Different from nwamd_triggered_check_all_conditions() in that this
783 * function enqueues a timed check event.
786 nwamd_set_timed_check_all_conditions(void)
788 nwamd_event_t check_event
= nwamd_event_init
789 (NWAM_EVENT_TYPE_TIMED_CHECK_CONDITIONS
, NWAM_OBJECT_TYPE_UNKNOWN
,
791 if (check_event
!= NULL
) {
792 /* Add another timed event to recheck conditions */
793 nwamd_event_enqueue_timed(check_event
,
794 condition_check_interval
> CONDITION_CHECK_INTERVAL_MIN
?
795 condition_check_interval
: CONDITION_CHECK_INTERVAL_MIN
);
800 * Does not enqueue another check event.
803 nwamd_check_all_conditions(void)
805 nwamd_enm_check_conditions();
806 nwamd_loc_check_conditions();
810 nwamd_create_timed_condition_check_event(void)
812 nwamd_event_t check_event
= nwamd_event_init
813 (NWAM_EVENT_TYPE_TIMED_CHECK_CONDITIONS
, NWAM_OBJECT_TYPE_UNKNOWN
,
815 if (check_event
!= NULL
)
816 nwamd_event_enqueue(check_event
);
820 nwamd_create_triggered_condition_check_event(uint32_t when
)
822 nwamd_event_t check_event
;
824 if (!nwamd_event_enqueued(NWAM_EVENT_TYPE_TRIGGERED_CHECK_CONDITIONS
,
825 NWAM_OBJECT_TYPE_UNKNOWN
, NULL
)) {
826 check_event
= nwamd_event_init
827 (NWAM_EVENT_TYPE_TRIGGERED_CHECK_CONDITIONS
,
828 NWAM_OBJECT_TYPE_UNKNOWN
, 0, NULL
);
829 if (check_event
!= NULL
)
830 nwamd_event_enqueue_timed(check_event
, when
);