2 * Copyright (c) 2018 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <sys/sysctl.h>
30 #include <sys/systm.h>
31 #include <sys/eventhandler.h>
35 #include <net/if_var.h>
36 #include <net/nwk_wq.h>
41 IF_LOW_POWER_EVENT_OFF
= 0,
42 IF_LOW_POWER_EVENT_ON
= 1
43 } if_low_power_ev_code_t
;
45 struct if_low_power_ev_args
{
47 if_low_power_ev_code_t event_code
;
50 struct if_low_power_ev_nwk_wq_entry
{
51 struct nwk_wq_entry nwk_wqe
;
52 struct if_low_power_ev_args ev_args
;
56 typedef void (*if_low_power_event_fn
) (struct eventhandler_entry_arg
,
57 struct ifnet
*, if_low_power_ev_code_t
);
58 EVENTHANDLER_DECLARE(if_low_power_event
, if_low_power_event_fn
);
60 struct eventhandler_lists_ctxt if_low_power_evhdlr_ctx
;
62 static void if_low_power_evhdlr_callback(__unused
struct eventhandler_entry_arg arg
,
63 struct ifnet
*ifp
, if_low_power_ev_code_t event_code
);
66 static void if_low_power_nwk_ev_callback(void *arg
);
67 static void if_low_power_event_enqueue_nwk_wq_entry(struct ifnet
*ifp
,
68 if_low_power_ev_code_t event_code
);
71 extern void shutdown_sockets_on_interface(struct ifnet
*ifp
);
73 SYSCTL_DECL(_net_link_generic_system
);
74 SYSCTL_NODE(_net_link_generic_system
, OID_AUTO
, low_power
,
75 CTLFLAG_RW
| CTLFLAG_LOCKED
, 0, "low power mode");
77 int if_low_power_verbose
= 0;
78 int if_low_power_restricted
= 1;
80 #if (DEVELOPMENT || DEBUG)
81 SYSCTL_INT(_net_link_generic_system_low_power
, OID_AUTO
, verbose
,
82 CTLFLAG_RW
| CTLFLAG_LOCKED
,
83 &if_low_power_verbose
, 0, "");
84 SYSCTL_INT(_net_link_generic_system_low_power
, OID_AUTO
, restricted
,
85 CTLFLAG_RW
| CTLFLAG_LOCKED
,
86 &if_low_power_restricted
, 0, "");
87 #endif /* (DEVELOPMENT || DEBUG) */
91 if_low_power_evhdlr_callback(__unused
struct eventhandler_entry_arg arg
,
92 struct ifnet
*ifp
, if_low_power_ev_code_t event_code
)
94 struct kev_dl_low_power_mode kev
;
96 if (!IF_FULLY_ATTACHED(ifp
))
99 if (if_low_power_verbose
> 0) {
100 os_log_info(OS_LOG_DEFAULT
,
101 "%s: ifp %s event_code %d", __func__
,
102 if_name(ifp
), event_code
);
105 ifnet_lock_exclusive(ifp
);
106 if (event_code
== IF_LOW_POWER_EVENT_OFF
) {
107 ifp
->if_xflags
&= ~IFXF_LOW_POWER
;
109 ifp
->if_xflags
|= IFXF_LOW_POWER
;
111 ifnet_lock_done(ifp
);
113 if (event_code
== IF_LOW_POWER_EVENT_ON
) {
114 atomic_add_32(&ifp
->if_low_power_gencnt
, 1);
116 if (if_low_power_restricted
!= 0) {
117 shutdown_sockets_on_interface(ifp
);
118 intf_event_enqueue_nwk_wq_entry(ifp
, NULL
,
119 INTF_EVENT_CODE_LOW_POWER_UPDATE
);
123 bzero(&kev
, sizeof(struct kev_dl_low_power_mode
));
124 kev
.low_power_event
= event_code
;
127 KEV_DL_LOW_POWER_MODE_CHANGED
,
128 (struct net_event_data
*)&kev
,
129 sizeof(struct kev_dl_low_power_mode
));
133 if_low_power_evhdlr_init(void)
135 eventhandler_lists_ctxt_init(&if_low_power_evhdlr_ctx
);
137 (void) EVENTHANDLER_REGISTER(&if_low_power_evhdlr_ctx
,
139 if_low_power_evhdlr_callback
,
140 eventhandler_entry_dummy_arg
,
141 EVENTHANDLER_PRI_ANY
);
146 if_low_power_nwk_ev_callback(void *arg
)
148 struct if_low_power_ev_args
*if_low_power_ev_args
=
149 (struct if_low_power_ev_args
*)arg
;
151 EVENTHANDLER_INVOKE(&if_low_power_evhdlr_ctx
,
153 if_low_power_ev_args
->ifp
,
154 if_low_power_ev_args
->event_code
);
158 if_low_power_event_enqueue_nwk_wq_entry(struct ifnet
*ifp
,
159 if_low_power_ev_code_t event_code
)
161 struct if_low_power_ev_nwk_wq_entry
*event_nwk_wq_entry
= NULL
;
163 MALLOC(event_nwk_wq_entry
, struct if_low_power_ev_nwk_wq_entry
*,
164 sizeof(struct if_low_power_ev_nwk_wq_entry
),
165 M_NWKWQ
, M_WAITOK
| M_ZERO
);
167 event_nwk_wq_entry
->ev_args
.ifp
= ifp
;
168 event_nwk_wq_entry
->ev_args
.event_code
= event_code
;
170 event_nwk_wq_entry
->nwk_wqe
.func
= if_low_power_nwk_ev_callback
;
171 event_nwk_wq_entry
->nwk_wqe
.is_arg_managed
= TRUE
;
172 event_nwk_wq_entry
->nwk_wqe
.arg
= &event_nwk_wq_entry
->ev_args
;
174 nwk_wq_enqueue((struct nwk_wq_entry
*)event_nwk_wq_entry
);
179 if_set_low_power(ifnet_t ifp
, bool on
)
186 os_log(OS_LOG_DEFAULT
,
187 "%s: ifp %s low_power mode %d", __func__
, if_name(ifp
), on
);
189 ifnet_lock_exclusive(ifp
);
190 ifp
->if_xflags
= on
? (ifp
->if_xflags
| IFXF_LOW_POWER
) :
191 (ifp
->if_xflags
& ~IFXF_LOW_POWER
);
192 ifnet_lock_done(ifp
);