1/*
2 * Copyright (c) 2017-2023 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <sys/types.h>
30#include <sys/sysctl.h>
31#include <sys/time.h>
32#include <sys/mcache.h>
33#include <sys/malloc.h>
34#include <sys/kauth.h>
35#include <sys/kern_event.h>
36#include <sys/bitstring.h>
37#include <sys/priv.h>
38#include <sys/proc.h>
39#include <sys/protosw.h>
40#include <sys/socket.h>
41
42#include <kern/locks.h>
43#include <kern/zalloc.h>
44
45#include <libkern/libkern.h>
46
47#include <net/kpi_interface.h>
48#include <net/if_var.h>
49#include <net/if_ports_used.h>
50
51#include <netinet/in_pcb.h>
52#include <netinet/ip.h>
53#include <netinet/ip6.h>
54#include <netinet/tcp_var.h>
55#include <netinet/tcp_fsm.h>
56#include <netinet/udp.h>
57
58#if SKYWALK
59#include <skywalk/os_skywalk_private.h>
60#include <skywalk/nexus/flowswitch/flow/flow_var.h>
61#include <skywalk/namespace/netns.h>
62#endif /* SKYWALK */
63
64#include <stdbool.h>
65
66#include <os/log.h>
67
68#define ESP_HDR_SIZE 4
69#define PORT_ISAKMP 500
70#define PORT_ISAKMP_NATT 4500 /* rfc3948 */
71
72#define IF_XNAME(ifp) ((ifp) != NULL ? (ifp)->if_xname : "")
73
74extern bool IOPMCopySleepWakeUUIDKey(char *buffer, size_t buf_len);
75
76SYSCTL_DECL(_net_link_generic_system);
77
78SYSCTL_NODE(_net_link_generic_system, OID_AUTO, port_used,
79 CTLFLAG_RW | CTLFLAG_LOCKED, 0, "if port used");
80
81struct if_ports_used_stats if_ports_used_stats = {};
82static int sysctl_if_ports_used_stats SYSCTL_HANDLER_ARGS;
83SYSCTL_PROC(_net_link_generic_system_port_used, OID_AUTO, stats,
84 CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0,
85 sysctl_if_ports_used_stats, "S,struct if_ports_used_stats", "");
86
87static uuid_t current_wakeuuid;
88SYSCTL_OPAQUE(_net_link_generic_system_port_used, OID_AUTO, current_wakeuuid,
89 CTLFLAG_RD | CTLFLAG_LOCKED,
90 current_wakeuuid, sizeof(uuid_t), "S,uuid_t", "");
91
92static int sysctl_net_port_info_list SYSCTL_HANDLER_ARGS;
93SYSCTL_PROC(_net_link_generic_system_port_used, OID_AUTO, list,
94 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0,
95 sysctl_net_port_info_list, "S,xnpigen", "");
96
97static int use_test_wakeuuid = 0;
98static uuid_t test_wakeuuid;
99
100#if (DEVELOPMENT || DEBUG)
101SYSCTL_INT(_net_link_generic_system_port_used, OID_AUTO, use_test_wakeuuid,
102 CTLFLAG_RW | CTLFLAG_LOCKED,
103 &use_test_wakeuuid, 0, "");
104
105int sysctl_new_test_wakeuuid SYSCTL_HANDLER_ARGS;
106SYSCTL_PROC(_net_link_generic_system_port_used, OID_AUTO, new_test_wakeuuid,
107 CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0,
108 sysctl_new_test_wakeuuid, "S,uuid_t", "");
109
110int sysctl_clear_test_wakeuuid SYSCTL_HANDLER_ARGS;
111SYSCTL_PROC(_net_link_generic_system_port_used, OID_AUTO, clear_test_wakeuuid,
112 CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0,
113 sysctl_clear_test_wakeuuid, "S,uuid_t", "");
114
115SYSCTL_OPAQUE(_net_link_generic_system_port_used, OID_AUTO, test_wakeuuid,
116 CTLFLAG_RD | CTLFLAG_LOCKED,
117 test_wakeuuid, sizeof(uuid_t), "S,uuid_t", "");
118#endif /* (DEVELOPMENT || DEBUG) */
119
120static int sysctl_get_ports_used SYSCTL_HANDLER_ARGS;
121SYSCTL_NODE(_net_link_generic_system, OID_AUTO, get_ports_used,
122 CTLFLAG_RD | CTLFLAG_LOCKED,
123 sysctl_get_ports_used, "");
124
125int if_ports_used_verbose = 0;
126SYSCTL_INT(_net_link_generic_system_port_used, OID_AUTO, verbose,
127 CTLFLAG_RW | CTLFLAG_LOCKED,
128 &if_ports_used_verbose, 0, "");
129
130struct timeval wakeuuid_not_set_last_time;
131int sysctl_wakeuuid_not_set_last_time SYSCTL_HANDLER_ARGS;
132static SYSCTL_PROC(_net_link_generic_system_port_used, OID_AUTO,
133 wakeuuid_not_set_last_time, CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED,
134 0, 0, sysctl_wakeuuid_not_set_last_time, "S,timeval", "");
135
136char wakeuuid_not_set_last_if[IFXNAMSIZ];
137int sysctl_wakeuuid_not_set_last_if SYSCTL_HANDLER_ARGS;
138static SYSCTL_PROC(_net_link_generic_system_port_used, OID_AUTO,
139 wakeuuid_not_set_last_if, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_LOCKED,
140 0, 0, sysctl_wakeuuid_not_set_last_if, "A", "");
141
142struct timeval wakeuuid_last_update_time;
143int sysctl_wakeuuid_last_update_time SYSCTL_HANDLER_ARGS;
144static SYSCTL_PROC(_net_link_generic_system_port_used, OID_AUTO,
145 wakeuuid_last_update_time, CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED,
146 0, 0, sysctl_wakeuuid_last_update_time, "S,timeval", "");
147
148struct net_port_info_wake_event last_attributed_wake_event;
149int sysctl_last_attributed_wake_event SYSCTL_HANDLER_ARGS;
150static SYSCTL_PROC(_net_link_generic_system_port_used, OID_AUTO,
151 last_attributed_wake_event, CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED,
152 0, 0, sysctl_last_attributed_wake_event, "S,net_port_info_wake_event", "");
153
154static bool last_wake_phy_if_set = false;
155static char last_wake_phy_if_name[IFNAMSIZ]; /* name + unit */
156static uint32_t last_wake_phy_if_family;
157static uint32_t last_wake_phy_if_subfamily;
158static uint32_t last_wake_phy_if_functional_type;
159
160
161static bool has_notified_wake_pkt = false;
162static bool has_notified_unattributed_wake = false;
163
164static LCK_GRP_DECLARE(net_port_entry_head_lock_group, "net port entry lock");
165static LCK_MTX_DECLARE(net_port_entry_head_lock, &net_port_entry_head_lock_group);
166
167
168struct net_port_entry {
169 SLIST_ENTRY(net_port_entry) npe_list_next;
170 TAILQ_ENTRY(net_port_entry) npe_hash_next;
171 struct net_port_info npe_npi;
172};
173
174static KALLOC_TYPE_DEFINE(net_port_entry_zone, struct net_port_entry, NET_KT_DEFAULT);
175
176static SLIST_HEAD(net_port_entry_list, net_port_entry) net_port_entry_list =
177 SLIST_HEAD_INITIALIZER(&net_port_entry_list);
178
179struct timeval wakeuiid_last_check;
180
181
182#if (DEBUG | DEVELOPMENT)
183static int64_t npi_search_list_total = 0;
184SYSCTL_QUAD(_net_link_generic_system_port_used, OID_AUTO, npi_search_list_total,
185 CTLFLAG_RD | CTLFLAG_LOCKED,
186 &npi_search_list_total, "");
187
188static int64_t npi_search_list_max = 0;
189SYSCTL_QUAD(_net_link_generic_system_port_used, OID_AUTO, npi_search_list_max,
190 CTLFLAG_RD | CTLFLAG_LOCKED,
191 &npi_search_list_max, "");
192#endif /* (DEBUG | DEVELOPMENT) */
193
194/*
195 * Hashing of the net_port_entry list is based on the local port
196 *
197 * The hash masks uses the least significant bits so we have to use host byte order
198 * when applying the mask because the LSB have more entropy that the MSB (most local ports
199 * are in the high dynamic port range)
200 */
201#define NPE_HASH_BUCKET_COUNT 32
202#define NPE_HASH_MASK (NPE_HASH_BUCKET_COUNT - 1)
203#define NPE_HASH_VAL(_lport) (ntohs(_lport) & NPE_HASH_MASK)
204#define NPE_HASH_HEAD(_lport) (&net_port_entry_hash_table[NPE_HASH_VAL(_lport)])
205
206static TAILQ_HEAD(net_port_entry_hash_table, net_port_entry) * net_port_entry_hash_table = NULL;
207
208/*
209 * Initialize IPv4 source address hash table.
210 */
211void
212if_ports_used_init(void)
213{
214 if (net_port_entry_hash_table != NULL) {
215 return;
216 }
217
218 net_port_entry_hash_table = zalloc_permanent(
219 NPE_HASH_BUCKET_COUNT * sizeof(*net_port_entry_hash_table),
220 ZALIGN_PTR);
221}
222
223static void
224net_port_entry_list_clear(void)
225{
226 struct net_port_entry *npe;
227
228 LCK_MTX_ASSERT(&net_port_entry_head_lock, LCK_MTX_ASSERT_OWNED);
229
230 while ((npe = SLIST_FIRST(&net_port_entry_list)) != NULL) {
231 SLIST_REMOVE_HEAD(&net_port_entry_list, npe_list_next);
232 TAILQ_REMOVE(NPE_HASH_HEAD(npe->npe_npi.npi_local_port), npe, npe_hash_next);
233
234 zfree(net_port_entry_zone, npe);
235 }
236
237 for (int i = 0; i < NPE_HASH_BUCKET_COUNT; i++) {
238 VERIFY(TAILQ_EMPTY(&net_port_entry_hash_table[i]));
239 }
240
241 if_ports_used_stats.ifpu_npe_count = 0;
242 if_ports_used_stats.ifpu_wakeuid_gen++;
243}
244
245static bool
246get_test_wake_uuid(uuid_string_t wakeuuid_str, size_t len)
247{
248 if (__improbable(use_test_wakeuuid)) {
249 if (!uuid_is_null(uu: test_wakeuuid)) {
250 if (wakeuuid_str != NULL && len != 0) {
251 uuid_unparse(uu: test_wakeuuid, out: wakeuuid_str);
252 }
253 return true;
254 } else {
255 return false;
256 }
257 } else {
258 return false;
259 }
260}
261
262static bool
263is_wakeuuid_set(void)
264{
265 /*
266 * IOPMCopySleepWakeUUIDKey() tells if SleepWakeUUID is currently set
267 * That means we are currently in a sleep/wake cycle
268 */
269 return get_test_wake_uuid(NULL, len: 0) || IOPMCopySleepWakeUUIDKey(NULL, buf_len: 0);
270}
271
272void
273if_ports_used_update_wakeuuid(struct ifnet *ifp)
274{
275 uuid_t wakeuuid;
276 bool wakeuuid_is_set = false;
277 bool updated = false;
278 uuid_string_t wakeuuid_str;
279
280 uuid_clear(uu: wakeuuid);
281
282 if (__improbable(use_test_wakeuuid)) {
283 wakeuuid_is_set = get_test_wake_uuid(wakeuuid_str,
284 len: sizeof(wakeuuid_str));
285 } else {
286 wakeuuid_is_set = IOPMCopySleepWakeUUIDKey(buffer: wakeuuid_str,
287 buf_len: sizeof(wakeuuid_str));
288 }
289
290 if (wakeuuid_is_set) {
291 if (uuid_parse(in: wakeuuid_str, uu: wakeuuid) != 0) {
292 os_log(OS_LOG_DEFAULT,
293 "%s: IOPMCopySleepWakeUUIDKey got bad value %s\n",
294 __func__, wakeuuid_str);
295 wakeuuid_is_set = false;
296 }
297 }
298
299 if (!wakeuuid_is_set) {
300 if (ifp != NULL) {
301 if (if_ports_used_verbose > 0) {
302 os_log_info(OS_LOG_DEFAULT,
303 "%s: SleepWakeUUID not set, "
304 "don't update the port list for %s\n",
305 __func__, ifp != NULL ? if_name(ifp) : "");
306 }
307 if_ports_used_stats.ifpu_wakeuuid_not_set_count += 1;
308 microtime(tv: &wakeuuid_not_set_last_time);
309 strlcpy(dst: wakeuuid_not_set_last_if, if_name(ifp),
310 n: sizeof(wakeuuid_not_set_last_if));
311 }
312 return;
313 }
314
315 lck_mtx_lock(lck: &net_port_entry_head_lock);
316 if (uuid_compare(uu1: wakeuuid, uu2: current_wakeuuid) != 0) {
317 net_port_entry_list_clear();
318 uuid_copy(dst: current_wakeuuid, src: wakeuuid);
319 microtime(tv: &wakeuuid_last_update_time);
320 updated = true;
321
322 has_notified_wake_pkt = false;
323 has_notified_unattributed_wake = false;
324
325 memset(s: &last_attributed_wake_event, c: 0, n: sizeof(last_attributed_wake_event));
326
327 last_wake_phy_if_set = false;
328 memset(s: &last_wake_phy_if_name, c: 0, n: sizeof(last_wake_phy_if_name));
329 last_wake_phy_if_family = IFRTYPE_FAMILY_ANY;
330 last_wake_phy_if_subfamily = IFRTYPE_SUBFAMILY_ANY;
331 last_wake_phy_if_functional_type = IFRTYPE_FUNCTIONAL_UNKNOWN;
332 }
333 /*
334 * Record the time last checked
335 */
336 microuptime(tv: &wakeuiid_last_check);
337 lck_mtx_unlock(lck: &net_port_entry_head_lock);
338
339 if (updated && if_ports_used_verbose > 0) {
340 uuid_string_t uuid_str;
341
342 uuid_unparse(uu: current_wakeuuid, out: uuid_str);
343 os_log(OS_LOG_DEFAULT, "%s: current wakeuuid %s",
344 __func__, uuid_str);
345 }
346}
347
348static bool
349net_port_info_equal(const struct net_port_info *x,
350 const struct net_port_info *y)
351{
352 ASSERT(x != NULL && y != NULL);
353
354 if (x->npi_if_index == y->npi_if_index &&
355 x->npi_local_port == y->npi_local_port &&
356 x->npi_foreign_port == y->npi_foreign_port &&
357 x->npi_owner_pid == y->npi_owner_pid &&
358 x->npi_effective_pid == y->npi_effective_pid &&
359 x->npi_flags == y->npi_flags &&
360 memcmp(s1: &x->npi_local_addr_, s2: &y->npi_local_addr_,
361 n: sizeof(union in_addr_4_6)) == 0 &&
362 memcmp(s1: &x->npi_foreign_addr_, s2: &y->npi_foreign_addr_,
363 n: sizeof(union in_addr_4_6)) == 0) {
364 return true;
365 }
366 return false;
367}
368
369static bool
370net_port_info_has_entry(const struct net_port_info *npi)
371{
372 struct net_port_entry *npe;
373 bool found = false;
374 int32_t count = 0;
375
376 LCK_MTX_ASSERT(&net_port_entry_head_lock, LCK_MTX_ASSERT_OWNED);
377
378 TAILQ_FOREACH(npe, NPE_HASH_HEAD(npi->npi_local_port), npe_hash_next) {
379 count += 1;
380 if (net_port_info_equal(x: &npe->npe_npi, y: npi)) {
381 found = true;
382 break;
383 }
384 }
385 if_ports_used_stats.ifpu_npi_hash_search_total += count;
386 if (count > if_ports_used_stats.ifpu_npi_hash_search_max) {
387 if_ports_used_stats.ifpu_npi_hash_search_max = count;
388 }
389
390 return found;
391}
392
393static bool
394net_port_info_add_entry(const struct net_port_info *npi)
395{
396 struct net_port_entry *npe = NULL;
397 uint32_t num = 0;
398 bool entry_added = false;
399
400 ASSERT(npi != NULL);
401
402 if (__improbable(is_wakeuuid_set() == false)) {
403 if_ports_used_stats.ifpu_npi_not_added_no_wakeuuid++;
404 if (if_ports_used_verbose > 0) {
405 os_log(OS_LOG_DEFAULT, "%s: wakeuuid not set not adding "
406 "port: %u flags: 0x%xif: %u pid: %u epid %u",
407 __func__,
408 ntohs(npi->npi_local_port),
409 npi->npi_flags,
410 npi->npi_if_index,
411 npi->npi_owner_pid,
412 npi->npi_effective_pid);
413 }
414 return false;
415 }
416
417 npe = zalloc_flags(net_port_entry_zone, Z_WAITOK | Z_ZERO);
418 if (__improbable(npe == NULL)) {
419 os_log(OS_LOG_DEFAULT, "%s: zalloc() failed for "
420 "port: %u flags: 0x%x if: %u pid: %u epid %u",
421 __func__,
422 ntohs(npi->npi_local_port),
423 npi->npi_flags,
424 npi->npi_if_index,
425 npi->npi_owner_pid,
426 npi->npi_effective_pid);
427 return false;
428 }
429
430 memcpy(dst: &npe->npe_npi, src: npi, n: sizeof(npe->npe_npi));
431
432 lck_mtx_lock(lck: &net_port_entry_head_lock);
433
434 if (net_port_info_has_entry(npi) == false) {
435 SLIST_INSERT_HEAD(&net_port_entry_list, npe, npe_list_next);
436 TAILQ_INSERT_HEAD(NPE_HASH_HEAD(npi->npi_local_port), npe, npe_hash_next);
437 num = (uint32_t)if_ports_used_stats.ifpu_npe_count++; /* rollover OK */
438 entry_added = true;
439
440 if (if_ports_used_stats.ifpu_npe_count > if_ports_used_stats.ifpu_npe_max) {
441 if_ports_used_stats.ifpu_npe_max = if_ports_used_stats.ifpu_npe_count;
442 }
443 if_ports_used_stats.ifpu_npe_total++;
444
445 if (if_ports_used_verbose > 1) {
446 os_log(OS_LOG_DEFAULT, "%s: num %u for "
447 "port: %u flags: 0x%x if: %u pid: %u epid %u",
448 __func__,
449 num,
450 ntohs(npi->npi_local_port),
451 npi->npi_flags,
452 npi->npi_if_index,
453 npi->npi_owner_pid,
454 npi->npi_effective_pid);
455 }
456 } else {
457 if_ports_used_stats.ifpu_npe_dup++;
458 if (if_ports_used_verbose > 2) {
459 os_log(OS_LOG_DEFAULT, "%s: already added "
460 "port: %u flags: 0x%x if: %u pid: %u epid %u",
461 __func__,
462 ntohs(npi->npi_local_port),
463 npi->npi_flags,
464 npi->npi_if_index,
465 npi->npi_owner_pid,
466 npi->npi_effective_pid);
467 }
468 }
469
470 lck_mtx_unlock(lck: &net_port_entry_head_lock);
471
472 if (entry_added == false) {
473 zfree(net_port_entry_zone, npe);
474 }
475 return entry_added;
476}
477
478#if (DEVELOPMENT || DEBUG)
479int
480sysctl_new_test_wakeuuid SYSCTL_HANDLER_ARGS
481{
482#pragma unused(oidp, arg1, arg2)
483 int error = 0;
484
485 if (kauth_cred_issuser(kauth_cred_get()) == 0) {
486 return EPERM;
487 }
488 if (req->oldptr == USER_ADDR_NULL) {
489 req->oldidx = sizeof(uuid_t);
490 return 0;
491 }
492 if (req->newptr != USER_ADDR_NULL) {
493 uuid_generate(test_wakeuuid);
494 if_ports_used_update_wakeuuid(NULL);
495 }
496 error = SYSCTL_OUT(req, test_wakeuuid,
497 MIN(sizeof(uuid_t), req->oldlen));
498
499 return error;
500}
501
502int
503sysctl_clear_test_wakeuuid SYSCTL_HANDLER_ARGS
504{
505#pragma unused(oidp, arg1, arg2)
506 int error = 0;
507
508 if (kauth_cred_issuser(kauth_cred_get()) == 0) {
509 return EPERM;
510 }
511 if (req->oldptr == USER_ADDR_NULL) {
512 req->oldidx = sizeof(uuid_t);
513 return 0;
514 }
515 if (req->newptr != USER_ADDR_NULL) {
516 uuid_clear(test_wakeuuid);
517 if_ports_used_update_wakeuuid(NULL);
518 }
519 error = SYSCTL_OUT(req, test_wakeuuid,
520 MIN(sizeof(uuid_t), req->oldlen));
521
522 return error;
523}
524
525#endif /* (DEVELOPMENT || DEBUG) */
526
527static int
528sysctl_timeval(struct sysctl_req *req, const struct timeval *tv)
529{
530 if (proc_is64bit(req->p)) {
531 struct user64_timeval tv64 = {};
532
533 tv64.tv_sec = tv->tv_sec;
534 tv64.tv_usec = tv->tv_usec;
535 return SYSCTL_OUT(req, &tv64, sizeof(tv64));
536 } else {
537 struct user32_timeval tv32 = {};
538
539 tv32.tv_sec = (user32_time_t)tv->tv_sec;
540 tv32.tv_usec = tv->tv_usec;
541 return SYSCTL_OUT(req, &tv32, sizeof(tv32));
542 }
543}
544
545int
546sysctl_wakeuuid_last_update_time SYSCTL_HANDLER_ARGS
547{
548#pragma unused(oidp, arg1, arg2)
549
550 return sysctl_timeval(req, tv: &wakeuuid_last_update_time);
551}
552
553int
554sysctl_wakeuuid_not_set_last_time SYSCTL_HANDLER_ARGS
555{
556#pragma unused(oidp, arg1, arg2)
557
558 return sysctl_timeval(req, tv: &wakeuuid_not_set_last_time);
559}
560
561int
562sysctl_wakeuuid_not_set_last_if SYSCTL_HANDLER_ARGS
563{
564#pragma unused(oidp, arg1, arg2)
565
566 return SYSCTL_OUT(req, &wakeuuid_not_set_last_if, strlen(wakeuuid_not_set_last_if) + 1);
567}
568
569int
570sysctl_if_ports_used_stats SYSCTL_HANDLER_ARGS
571{
572#pragma unused(oidp, arg1, arg2)
573 size_t len = sizeof(struct if_ports_used_stats);
574
575 if (req->oldptr != 0) {
576 len = MIN(req->oldlen, sizeof(struct if_ports_used_stats));
577 }
578 return SYSCTL_OUT(req, &if_ports_used_stats, len);
579}
580
581static int
582sysctl_net_port_info_list SYSCTL_HANDLER_ARGS
583{
584#pragma unused(oidp, arg1, arg2)
585 int error = 0;
586 struct xnpigen xnpigen;
587 struct net_port_entry *npe;
588
589 if ((error = priv_check_cred(cred: kauth_cred_get(),
590 PRIV_NET_PRIVILEGED_NETWORK_STATISTICS, flags: 0)) != 0) {
591 return EPERM;
592 }
593 lck_mtx_lock(lck: &net_port_entry_head_lock);
594
595 if (req->oldptr == USER_ADDR_NULL) {
596 /* Add a 25% cushion */
597 size_t cnt = (size_t)if_ports_used_stats.ifpu_npe_count;
598 cnt += cnt >> 4;
599 req->oldidx = sizeof(struct xnpigen) +
600 cnt * sizeof(struct net_port_info);
601 goto done;
602 }
603
604 memset(s: &xnpigen, c: 0, n: sizeof(struct xnpigen));
605 xnpigen.xng_len = sizeof(struct xnpigen);
606 xnpigen.xng_gen = (uint32_t)if_ports_used_stats.ifpu_wakeuid_gen;
607 uuid_copy(dst: xnpigen.xng_wakeuuid, src: current_wakeuuid);
608 xnpigen.xng_npi_count = (uint32_t)if_ports_used_stats.ifpu_npe_count;
609 xnpigen.xng_npi_size = sizeof(struct net_port_info);
610 error = SYSCTL_OUT(req, &xnpigen, sizeof(xnpigen));
611 if (error != 0) {
612 printf("%s: SYSCTL_OUT(xnpigen) error %d\n",
613 __func__, error);
614 goto done;
615 }
616
617 SLIST_FOREACH(npe, &net_port_entry_list, npe_list_next) {
618 error = SYSCTL_OUT(req, &npe->npe_npi,
619 sizeof(struct net_port_info));
620 if (error != 0) {
621 printf("%s: SYSCTL_OUT(npi) error %d\n",
622 __func__, error);
623 goto done;
624 }
625 }
626done:
627 lck_mtx_unlock(lck: &net_port_entry_head_lock);
628
629 return error;
630}
631
632/*
633 * Mirror the arguments of ifnet_get_local_ports_extended()
634 * ifindex
635 * protocol
636 * flags
637 */
638static int
639sysctl_get_ports_used SYSCTL_HANDLER_ARGS
640{
641#pragma unused(oidp)
642 int *name = (int *)arg1;
643 int namelen = arg2;
644 int error = 0;
645 int idx;
646 protocol_family_t protocol;
647 u_int32_t flags;
648 ifnet_t ifp = NULL;
649 u_int8_t *bitfield = NULL;
650
651 if (req->newptr != USER_ADDR_NULL) {
652 error = EPERM;
653 goto done;
654 }
655 /*
656 * 3 is the required number of parameters: ifindex, protocol and flags
657 */
658 if (namelen != 3) {
659 error = ENOENT;
660 goto done;
661 }
662
663 if (req->oldptr == USER_ADDR_NULL) {
664 req->oldidx = bitstr_size(IP_PORTRANGE_SIZE);
665 goto done;
666 }
667 if (req->oldlen < bitstr_size(IP_PORTRANGE_SIZE)) {
668 error = ENOMEM;
669 goto done;
670 }
671 bitfield = (u_int8_t *) kalloc_data(bitstr_size(IP_PORTRANGE_SIZE),
672 Z_WAITOK | Z_ZERO);
673 if (bitfield == NULL) {
674 error = ENOMEM;
675 goto done;
676 }
677
678 idx = name[0];
679 protocol = name[1];
680 flags = name[2];
681
682 ifnet_head_lock_shared();
683 if (IF_INDEX_IN_RANGE(idx)) {
684 ifp = ifindex2ifnet[idx];
685 }
686 ifnet_head_done();
687
688 error = ifnet_get_local_ports_extended(ifp, protocol, flags, bitfield);
689 if (error != 0) {
690 printf("%s: ifnet_get_local_ports_extended() error %d\n",
691 __func__, error);
692 goto done;
693 }
694 error = SYSCTL_OUT(req, bitfield, bitstr_size(IP_PORTRANGE_SIZE));
695done:
696 if (bitfield != NULL) {
697 kfree_data(bitfield, bitstr_size(IP_PORTRANGE_SIZE));
698 }
699 return error;
700}
701
702__private_extern__ bool
703if_ports_used_add_inpcb(const uint32_t ifindex, const struct inpcb *inp)
704{
705 struct net_port_info npi = {};
706 struct socket *so = inp->inp_socket;
707
708 /* This is unlikely to happen but better be safe than sorry */
709 if (ifindex > UINT16_MAX) {
710 os_log(OS_LOG_DEFAULT, "%s: ifindex %u too big", __func__, ifindex);
711 return false;
712 }
713
714 if (ifindex != 0) {
715 npi.npi_if_index = (uint16_t)ifindex;
716 } else if (inp->inp_last_outifp != NULL) {
717 npi.npi_if_index = (uint16_t)inp->inp_last_outifp->if_index;
718 }
719 if (IF_INDEX_IN_RANGE(npi.npi_if_index)) {
720 struct ifnet *ifp = ifindex2ifnet[npi.npi_if_index];
721 if (ifp != NULL && IFNET_IS_COMPANION_LINK(ifp)) {
722 npi.npi_flags |= NPIF_COMPLINK;
723 }
724 }
725
726 npi.npi_flags |= NPIF_SOCKET;
727
728 npi.npi_timestamp.tv_sec = (int32_t)wakeuiid_last_check.tv_sec;
729 npi.npi_timestamp.tv_usec = wakeuiid_last_check.tv_usec;
730
731 if (so->so_options & SO_NOWAKEFROMSLEEP) {
732 npi.npi_flags |= NPIF_NOWAKE;
733 }
734
735 if (SOCK_PROTO(so) == IPPROTO_TCP) {
736 struct tcpcb *tp = intotcpcb(inp);
737
738 npi.npi_flags |= NPIF_TCP;
739 if (tp != NULL && tp->t_state == TCPS_LISTEN) {
740 npi.npi_flags |= NPIF_LISTEN;
741 }
742 } else if (SOCK_PROTO(so) == IPPROTO_UDP) {
743 npi.npi_flags |= NPIF_UDP;
744 } else {
745 os_log(OS_LOG_DEFAULT, "%s: unexpected protocol %u for inp %p", __func__,
746 SOCK_PROTO(inp->inp_socket), inp);
747 return false;
748 }
749
750 uuid_copy(dst: npi.npi_flow_uuid, src: inp->necp_client_uuid);
751
752 npi.npi_local_port = inp->inp_lport;
753 npi.npi_foreign_port = inp->inp_fport;
754
755 /*
756 * Take in account IPv4 addresses mapped on IPv6
757 */
758 if ((inp->inp_vflag & INP_IPV6) != 0 && (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 &&
759 (inp->inp_vflag & (INP_IPV6 | INP_IPV4)) == (INP_IPV6 | INP_IPV4)) {
760 npi.npi_flags |= NPIF_IPV6 | NPIF_IPV4;
761 memcpy(dst: &npi.npi_local_addr_in6,
762 src: &inp->in6p_laddr, n: sizeof(struct in6_addr));
763 } else if (inp->inp_vflag & INP_IPV4) {
764 npi.npi_flags |= NPIF_IPV4;
765 npi.npi_local_addr_in = inp->inp_laddr;
766 npi.npi_foreign_addr_in = inp->inp_faddr;
767 } else {
768 npi.npi_flags |= NPIF_IPV6;
769 memcpy(dst: &npi.npi_local_addr_in6,
770 src: &inp->in6p_laddr, n: sizeof(struct in6_addr));
771 memcpy(dst: &npi.npi_foreign_addr_in6,
772 src: &inp->in6p_faddr, n: sizeof(struct in6_addr));
773
774 /* Clear the embedded scope ID */
775 if (IN6_IS_ADDR_LINKLOCAL(&npi.npi_local_addr_in6)) {
776 npi.npi_local_addr_in6.s6_addr16[1] = 0;
777 }
778 if (IN6_IS_ADDR_LINKLOCAL(&npi.npi_foreign_addr_in6)) {
779 npi.npi_foreign_addr_in6.s6_addr16[1] = 0;
780 }
781 }
782
783 npi.npi_owner_pid = so->last_pid;
784
785 if (so->last_pid != 0) {
786 proc_name(pid: so->last_pid, buf: npi.npi_owner_pname,
787 size: sizeof(npi.npi_owner_pname));
788 uuid_copy(dst: npi.npi_owner_uuid, src: so->last_uuid);
789 }
790
791 if (so->so_flags & SOF_DELEGATED) {
792 npi.npi_flags |= NPIF_DELEGATED;
793 npi.npi_effective_pid = so->e_pid;
794 if (so->e_pid != 0) {
795 proc_name(pid: so->e_pid, buf: npi.npi_effective_pname,
796 size: sizeof(npi.npi_effective_pname));
797 }
798 uuid_copy(dst: npi.npi_effective_uuid, src: so->e_uuid);
799 } else {
800 npi.npi_effective_pid = so->last_pid;
801 if (so->last_pid != 0) {
802 strlcpy(dst: npi.npi_effective_pname, src: npi.npi_owner_pname,
803 n: sizeof(npi.npi_effective_pname));
804 }
805 uuid_copy(dst: npi.npi_effective_uuid, src: so->last_uuid);
806 }
807
808 return net_port_info_add_entry(npi: &npi);
809}
810
811#if SKYWALK
812__private_extern__ bool
813if_ports_used_add_flow_entry(const struct flow_entry *fe, const uint32_t ifindex,
814 const struct ns_flow_info *nfi, uint32_t ns_flags)
815{
816 struct net_port_info npi = {};
817
818 /* This is unlikely to happen but better be safe than sorry */
819 if (ifindex > UINT16_MAX) {
820 os_log(OS_LOG_DEFAULT, "%s: ifindex %u too big", __func__, ifindex);
821 return false;
822 }
823 npi.npi_if_index = (uint16_t)ifindex;
824 if (IF_INDEX_IN_RANGE(ifindex)) {
825 struct ifnet *ifp = ifindex2ifnet[ifindex];
826 if (ifp != NULL && IFNET_IS_COMPANION_LINK(ifp)) {
827 npi.npi_flags |= NPIF_COMPLINK;
828 }
829 }
830
831 npi.npi_flags |= NPIF_CHANNEL;
832
833 npi.npi_timestamp.tv_sec = (int32_t)wakeuiid_last_check.tv_sec;
834 npi.npi_timestamp.tv_usec = wakeuiid_last_check.tv_usec;
835
836 if (ns_flags & NETNS_NOWAKEFROMSLEEP) {
837 npi.npi_flags |= NPIF_NOWAKE;
838 }
839 if ((ns_flags & NETNS_OWNER_MASK) == NETNS_LISTENER) {
840 npi.npi_flags |= NPIF_LISTEN;
841 }
842
843 uuid_copy(dst: npi.npi_flow_uuid, src: nfi->nfi_flow_uuid);
844
845 if (nfi->nfi_protocol == IPPROTO_TCP) {
846 npi.npi_flags |= NPIF_TCP;
847 } else if (nfi->nfi_protocol == IPPROTO_UDP) {
848 npi.npi_flags |= NPIF_UDP;
849 } else {
850 os_log(OS_LOG_DEFAULT, "%s: unexpected protocol %u for nfi %p",
851 __func__, nfi->nfi_protocol, nfi);
852 return false;
853 }
854
855 if (nfi->nfi_laddr.sa.sa_family == AF_INET) {
856 npi.npi_flags |= NPIF_IPV4;
857
858 npi.npi_local_port = nfi->nfi_laddr.sin.sin_port;
859 npi.npi_foreign_port = nfi->nfi_faddr.sin.sin_port;
860
861 npi.npi_local_addr_in = nfi->nfi_laddr.sin.sin_addr;
862 npi.npi_foreign_addr_in = nfi->nfi_faddr.sin.sin_addr;
863 } else {
864 npi.npi_flags |= NPIF_IPV6;
865
866 npi.npi_local_port = nfi->nfi_laddr.sin6.sin6_port;
867 npi.npi_foreign_port = nfi->nfi_faddr.sin6.sin6_port;
868
869 memcpy(dst: &npi.npi_local_addr_in6,
870 src: &nfi->nfi_laddr.sin6.sin6_addr, n: sizeof(struct in6_addr));
871 memcpy(dst: &npi.npi_foreign_addr_in6,
872 src: &nfi->nfi_faddr.sin6.sin6_addr, n: sizeof(struct in6_addr));
873
874 /* Clear the embedded scope ID */
875 if (IN6_IS_ADDR_LINKLOCAL(&npi.npi_local_addr_in6)) {
876 npi.npi_local_addr_in6.s6_addr16[1] = 0;
877 }
878 if (IN6_IS_ADDR_LINKLOCAL(&npi.npi_foreign_addr_in6)) {
879 npi.npi_foreign_addr_in6.s6_addr16[1] = 0;
880 }
881 }
882
883 npi.npi_owner_pid = nfi->nfi_owner_pid;
884 strlcpy(dst: npi.npi_owner_pname, src: nfi->nfi_owner_name,
885 n: sizeof(npi.npi_owner_pname));
886
887 /*
888 * Get the proc UUID from the pid as the the proc UUID is not present
889 * in the flow_entry
890 */
891 proc_t proc = proc_find(pid: npi.npi_owner_pid);
892 if (proc != PROC_NULL) {
893 proc_getexecutableuuid(proc, npi.npi_owner_uuid, sizeof(npi.npi_owner_uuid));
894 proc_rele(p: proc);
895 }
896 if (nfi->nfi_effective_pid != -1) {
897 npi.npi_effective_pid = nfi->nfi_effective_pid;
898 strlcpy(dst: npi.npi_effective_pname, src: nfi->nfi_effective_name,
899 n: sizeof(npi.npi_effective_pname));
900 uuid_copy(dst: npi.npi_effective_uuid, src: fe->fe_eproc_uuid);
901 } else {
902 npi.npi_effective_pid = npi.npi_owner_pid;
903 strlcpy(dst: npi.npi_effective_pname, src: npi.npi_owner_pname,
904 n: sizeof(npi.npi_effective_pname));
905 uuid_copy(dst: npi.npi_effective_uuid, src: npi.npi_owner_uuid);
906 }
907
908 return net_port_info_add_entry(npi: &npi);
909}
910
911#endif /* SKYWALK */
912
913static void
914net_port_info_log_npi(const char *s, const struct net_port_info *npi)
915{
916 char lbuf[MAX_IPv6_STR_LEN] = {};
917 char fbuf[MAX_IPv6_STR_LEN] = {};
918
919 if (npi->npi_flags & NPIF_IPV4) {
920 inet_ntop(PF_INET, &npi->npi_local_addr_in.s_addr,
921 lbuf, sizeof(lbuf));
922 inet_ntop(PF_INET, &npi->npi_foreign_addr_in.s_addr,
923 fbuf, sizeof(fbuf));
924 } else if (npi->npi_flags & NPIF_IPV6) {
925 inet_ntop(PF_INET6, &npi->npi_local_addr_in6,
926 lbuf, sizeof(lbuf));
927 inet_ntop(PF_INET6, &npi->npi_foreign_addr_in6,
928 fbuf, sizeof(fbuf));
929 }
930 os_log(OS_LOG_DEFAULT, "%s net_port_info if_index %u arch %s family %s proto %s local %s:%u foreign %s:%u pid: %u epid %u",
931 s != NULL ? s : "",
932 npi->npi_if_index,
933 (npi->npi_flags & NPIF_SOCKET) ? "so" : (npi->npi_flags & NPIF_CHANNEL) ? "ch" : "unknown",
934 (npi->npi_flags & NPIF_IPV4) ? "ipv4" : (npi->npi_flags & NPIF_IPV6) ? "ipv6" : "unknown",
935 npi->npi_flags & NPIF_TCP ? "tcp" : npi->npi_flags & NPIF_UDP ? "udp" :
936 npi->npi_flags & NPIF_ESP ? "esp" : "unknown",
937 lbuf, ntohs(npi->npi_local_port),
938 fbuf, ntohs(npi->npi_foreign_port),
939 npi->npi_owner_pid,
940 npi->npi_effective_pid);
941}
942
943/*
944 * net_port_info_match_npi() returns true for an exact match that does not have "no wake" set
945 */
946#define NPI_MATCH_IPV4 (NPIF_IPV4 | NPIF_TCP | NPIF_UDP)
947#define NPI_MATCH_IPV6 (NPIF_IPV6 | NPIF_TCP | NPIF_UDP)
948
949static bool
950net_port_info_match_npi(struct net_port_entry *npe, const struct net_port_info *in_npi,
951 struct net_port_entry **best_match)
952{
953 if (__improbable(net_wake_pkt_debug > 1)) {
954 net_port_info_log_npi(s: " ", npi: &npe->npe_npi);
955 }
956
957 /*
958 * The interfaces must match or be both companion link
959 */
960 if (npe->npe_npi.npi_if_index != in_npi->npi_if_index &&
961 !((npe->npe_npi.npi_flags & NPIF_COMPLINK) && (in_npi->npi_flags & NPIF_COMPLINK))) {
962 return false;
963 }
964
965 /*
966 * The local ports and protocols must match
967 */
968 if (npe->npe_npi.npi_local_port != in_npi->npi_local_port ||
969 ((npe->npe_npi.npi_flags & NPI_MATCH_IPV4) != (in_npi->npi_flags & NPI_MATCH_IPV4) &&
970 (npe->npe_npi.npi_flags & NPI_MATCH_IPV6) != (in_npi->npi_flags & NPI_MATCH_IPV6))) {
971 return false;
972 }
973
974 /*
975 * Search stops on an exact match
976 */
977 if (npe->npe_npi.npi_foreign_port == in_npi->npi_foreign_port) {
978 if ((npe->npe_npi.npi_flags & NPIF_IPV4) && (npe->npe_npi.npi_flags & NPIF_IPV4)) {
979 if (in_npi->npi_local_addr_in.s_addr == npe->npe_npi.npi_local_addr_in.s_addr &&
980 in_npi->npi_foreign_addr_in.s_addr == npe->npe_npi.npi_foreign_addr_in.s_addr) {
981 if (npe->npe_npi.npi_flags & NPIF_NOWAKE) {
982 /*
983 * Do not overwrite an existing match when "no wake" is set
984 */
985 if (*best_match == NULL) {
986 *best_match = npe;
987 }
988 return false;
989 }
990 *best_match = npe;
991 return true;
992 }
993 }
994 if ((npe->npe_npi.npi_flags & NPIF_IPV6) && (npe->npe_npi.npi_flags & NPIF_IPV6)) {
995 if (memcmp(s1: &npe->npe_npi.npi_local_addr_, s2: &in_npi->npi_local_addr_,
996 n: sizeof(union in_addr_4_6)) == 0 &&
997 memcmp(s1: &npe->npe_npi.npi_foreign_addr_, s2: &in_npi->npi_foreign_addr_,
998 n: sizeof(union in_addr_4_6)) == 0) {
999 if (npe->npe_npi.npi_flags & NPIF_NOWAKE) {
1000 /*
1001 * Do not overwrite an existing match when "no wake" is set
1002 */
1003 if (*best_match == NULL) {
1004 *best_match = npe;
1005 }
1006 return false;
1007 }
1008 *best_match = npe;
1009 return true;
1010 }
1011 }
1012 }
1013 /*
1014 * Skip connected entries as we are looking for a wildcard match
1015 * on the local address and port
1016 */
1017 if (npe->npe_npi.npi_foreign_port != 0) {
1018 return false;
1019 }
1020 /*
1021 * Do not overwrite an existing match when "no wake" is set
1022 */
1023 if (*best_match != NULL && (npe->npe_npi.npi_flags & NPIF_NOWAKE) != 0) {
1024 return false;
1025 }
1026 /*
1027 * The local address matches: this is our 2nd best match
1028 */
1029 if (memcmp(s1: &npe->npe_npi.npi_local_addr_, s2: &in_npi->npi_local_addr_,
1030 n: sizeof(union in_addr_4_6)) == 0) {
1031 *best_match = npe;
1032 return false;
1033 }
1034
1035 /*
1036 * Only the local port matches, do not override a match
1037 * on the local address
1038 */
1039 if (*best_match == NULL) {
1040 *best_match = npe;
1041 }
1042 return false;
1043}
1044#undef NPI_MATCH_IPV4
1045#undef NPI_MATCH_IPV6
1046
1047/*
1048 *
1049 */
1050static bool
1051net_port_info_find_match(struct net_port_info *in_npi)
1052{
1053 struct net_port_entry *npe;
1054 struct net_port_entry *best_match = NULL;
1055
1056 lck_mtx_lock(lck: &net_port_entry_head_lock);
1057
1058 uint32_t count = 0;
1059 TAILQ_FOREACH(npe, NPE_HASH_HEAD(in_npi->npi_local_port), npe_hash_next) {
1060 count += 1;
1061 /*
1062 * Search stop on an exact match
1063 */
1064 if (net_port_info_match_npi(npe, in_npi, best_match: &best_match)) {
1065 break;
1066 }
1067 }
1068
1069 if (best_match != NULL) {
1070 best_match->npe_npi.npi_flags |= NPIF_WAKEPKT;
1071 if (best_match->npe_npi.npi_flags & NPIF_NOWAKE) {
1072 in_npi->npi_flags |= NPIF_NOWAKE;
1073 }
1074 in_npi->npi_owner_pid = best_match->npe_npi.npi_owner_pid;
1075 in_npi->npi_effective_pid = best_match->npe_npi.npi_effective_pid;
1076 strlcpy(dst: in_npi->npi_owner_pname, src: best_match->npe_npi.npi_owner_pname,
1077 n: sizeof(in_npi->npi_owner_pname));
1078 strlcpy(dst: in_npi->npi_effective_pname, src: best_match->npe_npi.npi_effective_pname,
1079 n: sizeof(in_npi->npi_effective_pname));
1080 uuid_copy(dst: in_npi->npi_owner_uuid, src: best_match->npe_npi.npi_owner_uuid);
1081 uuid_copy(dst: in_npi->npi_effective_uuid, src: best_match->npe_npi.npi_effective_uuid);
1082 }
1083 lck_mtx_unlock(lck: &net_port_entry_head_lock);
1084
1085 if (__improbable(net_wake_pkt_debug > 0)) {
1086 if (best_match != NULL) {
1087 net_port_info_log_npi(s: "wake packet match", npi: in_npi);
1088 } else {
1089 net_port_info_log_npi(s: "wake packet no match", npi: in_npi);
1090 }
1091 }
1092
1093 return best_match != NULL ? true : false;
1094}
1095
1096#if (DEBUG || DEVELOPMENT)
1097static void
1098net_port_info_log_una_wake_event(const char *s, struct net_port_info_una_wake_event *ev)
1099{
1100 char lbuf[MAX_IPv6_STR_LEN] = {};
1101 char fbuf[MAX_IPv6_STR_LEN] = {};
1102
1103 if (ev->una_wake_pkt_flags & NPIF_IPV4) {
1104 inet_ntop(PF_INET, &ev->una_wake_pkt_local_addr_._in_a_4.s_addr,
1105 lbuf, sizeof(lbuf));
1106 inet_ntop(PF_INET, &ev->una_wake_pkt_foreign_addr_._in_a_4.s_addr,
1107 fbuf, sizeof(fbuf));
1108 } else if (ev->una_wake_pkt_flags & NPIF_IPV6) {
1109 inet_ntop(PF_INET6, &ev->una_wake_pkt_local_addr_._in_a_6.s6_addr,
1110 lbuf, sizeof(lbuf));
1111 inet_ntop(PF_INET6, &ev->una_wake_pkt_foreign_addr_._in_a_6.s6_addr,
1112 fbuf, sizeof(fbuf));
1113 }
1114 os_log(OS_LOG_DEFAULT, "%s if %s (%u) phy_if %s proto %s local %s:%u foreign %s:%u len: %u datalen: %u cflags: 0x%x proto: %u",
1115 s != NULL ? s : "",
1116 ev->una_wake_pkt_ifname, ev->una_wake_pkt_if_index, ev->una_wake_pkt_phy_ifname,
1117 ev->una_wake_pkt_flags & NPIF_TCP ? "tcp" : ev->una_wake_pkt_flags ? "udp" :
1118 ev->una_wake_pkt_flags & NPIF_ESP ? "esp" : "unknown",
1119 lbuf, ntohs(ev->una_wake_pkt_local_port),
1120 fbuf, ntohs(ev->una_wake_pkt_foreign_port),
1121 ev->una_wake_pkt_total_len, ev->una_wake_pkt_data_len,
1122 ev->una_wake_pkt_control_flags, ev->una_wake_pkt_proto);
1123}
1124
1125static void
1126net_port_info_log_wake_event(const char *s, struct net_port_info_wake_event *ev)
1127{
1128 char lbuf[MAX_IPv6_STR_LEN] = {};
1129 char fbuf[MAX_IPv6_STR_LEN] = {};
1130
1131 if (ev->wake_pkt_flags & NPIF_IPV4) {
1132 inet_ntop(PF_INET, &ev->wake_pkt_local_addr_._in_a_4.s_addr,
1133 lbuf, sizeof(lbuf));
1134 inet_ntop(PF_INET, &ev->wake_pkt_foreign_addr_._in_a_4.s_addr,
1135 fbuf, sizeof(fbuf));
1136 } else if (ev->wake_pkt_flags & NPIF_IPV6) {
1137 inet_ntop(PF_INET6, &ev->wake_pkt_local_addr_._in_a_6.s6_addr,
1138 lbuf, sizeof(lbuf));
1139 inet_ntop(PF_INET6, &ev->wake_pkt_foreign_addr_._in_a_6.s6_addr,
1140 fbuf, sizeof(fbuf));
1141 }
1142 os_log(OS_LOG_DEFAULT, "%s if %s (%u) phy_if %s proto %s local %s:%u foreign %s:%u len: %u datalen: %u cflags: 0x%x proc %s eproc %s",
1143 s != NULL ? s : "",
1144 ev->wake_pkt_ifname, ev->wake_pkt_if_index, ev->wake_pkt_phy_ifname,
1145 ev->wake_pkt_flags & NPIF_TCP ? "tcp" : ev->wake_pkt_flags ? "udp" :
1146 ev->wake_pkt_flags & NPIF_ESP ? "esp" : "unknown",
1147 lbuf, ntohs(ev->wake_pkt_port),
1148 fbuf, ntohs(ev->wake_pkt_foreign_port),
1149 ev->wake_pkt_total_len, ev->wake_pkt_data_len, ev->wake_pkt_control_flags,
1150 ev->wake_pkt_owner_pname, ev->wake_pkt_effective_pname);
1151}
1152
1153#endif /* (DEBUG || DEVELOPMENT) */
1154
1155/*
1156 * The process attribution of a wake packet can take several steps:
1157 *
1158 * 1) After device wakes, the first interface that sees a wake packet is the
1159 * physical interface and we remember it via if_set_wake_physical_interface()
1160 *
1161 * 2) We try to attribute a packet to a flow or not based on the physical interface.
1162 * If we find a flow, then the physical interface is the same as the interface used
1163 * by the TCP/UDP flow.
1164 *
1165 * 3) If the packet is tunneled or redirected we are going to do the attribution again
1166 * and the physical will be different from the interface used the TCP/UDP flow.
1167 */
1168static void
1169if_set_wake_physical_interface(struct ifnet *ifp)
1170{
1171 if (last_wake_phy_if_set == true || ifp == NULL) {
1172 return;
1173 }
1174 last_wake_phy_if_set = true;
1175 strlcpy(dst: last_wake_phy_if_name, IF_XNAME(ifp), n: sizeof(last_wake_phy_if_name));
1176 last_wake_phy_if_family = ifp->if_family;
1177 last_wake_phy_if_subfamily = ifp->if_subfamily;
1178 last_wake_phy_if_functional_type = if_functional_type(ifp, true);
1179}
1180
1181static void
1182if_notify_unattributed_wake_mbuf(struct ifnet *ifp, struct mbuf *m,
1183 struct net_port_info *npi, uint32_t pkt_total_len, uint32_t pkt_data_len,
1184 uint16_t pkt_control_flags, uint16_t proto)
1185{
1186 struct kev_msg ev_msg = {};
1187
1188 LCK_MTX_ASSERT(&net_port_entry_head_lock, LCK_MTX_ASSERT_NOTOWNED);
1189
1190 lck_mtx_lock(lck: &net_port_entry_head_lock);
1191 if (has_notified_unattributed_wake) {
1192 lck_mtx_unlock(lck: &net_port_entry_head_lock);
1193 if_ports_used_stats.ifpu_dup_unattributed_wake_event += 1;
1194
1195 if (__improbable(net_wake_pkt_debug > 0)) {
1196 net_port_info_log_npi(s: "already notified unattributed wake packet", npi);
1197 }
1198 return;
1199 }
1200 has_notified_unattributed_wake = true;
1201 lck_mtx_unlock(lck: &net_port_entry_head_lock);
1202
1203 if_ports_used_stats.ifpu_unattributed_wake_event += 1;
1204
1205 ev_msg.vendor_code = KEV_VENDOR_APPLE;
1206 ev_msg.kev_class = KEV_NETWORK_CLASS;
1207 ev_msg.kev_subclass = KEV_POWER_SUBCLASS;
1208 ev_msg.event_code = KEV_POWER_UNATTRIBUTED_WAKE;
1209
1210 struct net_port_info_una_wake_event event_data = {};
1211 uuid_copy(dst: event_data.una_wake_uuid, src: current_wakeuuid);
1212 event_data.una_wake_pkt_if_index = ifp != NULL ? ifp->if_index : 0;
1213 event_data.una_wake_pkt_flags = npi->npi_flags;
1214
1215 event_data.una_wake_pkt_local_port = npi->npi_local_port;
1216 event_data.una_wake_pkt_foreign_port = npi->npi_foreign_port;
1217 event_data.una_wake_pkt_local_addr_ = npi->npi_local_addr_;
1218 event_data.una_wake_pkt_foreign_addr_ = npi->npi_foreign_addr_;
1219
1220 event_data.una_wake_pkt_total_len = pkt_total_len;
1221 event_data.una_wake_pkt_data_len = pkt_data_len;
1222 event_data.una_wake_pkt_control_flags = pkt_control_flags;
1223 event_data.una_wake_pkt_proto = proto;
1224
1225 if (ifp != NULL) {
1226 strlcpy(dst: event_data.una_wake_pkt_ifname, IF_XNAME(ifp),
1227 n: sizeof(event_data.una_wake_pkt_ifname));
1228 event_data.una_wake_pkt_if_info.npi_if_family = ifp->if_family;
1229 event_data.una_wake_pkt_if_info.npi_if_subfamily = ifp->if_subfamily;
1230 event_data.una_wake_pkt_if_info.npi_if_functional_type = if_functional_type(ifp, true);
1231
1232 strlcpy(dst: event_data.una_wake_pkt_phy_ifname, src: last_wake_phy_if_name,
1233 n: sizeof(event_data.una_wake_pkt_phy_ifname));
1234 event_data.una_wake_pkt_phy_if_info.npi_if_family = last_wake_phy_if_family;
1235 event_data.una_wake_pkt_phy_if_info.npi_if_subfamily = last_wake_phy_if_subfamily;
1236 event_data.una_wake_pkt_phy_if_info.npi_if_functional_type = last_wake_phy_if_functional_type;
1237 } else {
1238 if_ports_used_stats.ifpu_unattributed_null_recvif += 1;
1239 }
1240
1241 event_data.una_wake_ptk_len = m->m_pkthdr.len > NPI_MAX_UNA_WAKE_PKT_LEN ?
1242 NPI_MAX_UNA_WAKE_PKT_LEN : (u_int16_t)m->m_pkthdr.len;
1243
1244 errno_t error = mbuf_copydata(mbuf: m, offset: 0, length: event_data.una_wake_ptk_len,
1245 out_data: (void *)event_data.una_wake_pkt);
1246 if (error != 0) {
1247 uuid_string_t wake_uuid_str;
1248
1249 uuid_unparse(uu: event_data.una_wake_uuid, out: wake_uuid_str);
1250 os_log_error(OS_LOG_DEFAULT,
1251 "%s: mbuf_copydata() failed with error %d for wake uuid %s",
1252 __func__, error, wake_uuid_str);
1253
1254 if_ports_used_stats.ifpu_unattributed_wake_event_error += 1;
1255 return;
1256 }
1257
1258 ev_msg.dv[0].data_ptr = &event_data;
1259 ev_msg.dv[0].data_length = sizeof(event_data);
1260
1261 int result = kev_post_msg(event: &ev_msg);
1262 if (result != 0) {
1263 uuid_string_t wake_uuid_str;
1264
1265 uuid_unparse(uu: event_data.una_wake_uuid, out: wake_uuid_str);
1266 os_log_error(OS_LOG_DEFAULT,
1267 "%s: kev_post_msg() failed with error %d for wake uuid %s",
1268 __func__, result, wake_uuid_str);
1269
1270 if_ports_used_stats.ifpu_unattributed_wake_event_error += 1;
1271 }
1272
1273#if (DEBUG || DEVELOPMENT)
1274 net_port_info_log_una_wake_event("unattributed wake packet event", &event_data);
1275#endif /* (DEBUG || DEVELOPMENT) */
1276}
1277
1278static void
1279if_notify_wake_packet(struct ifnet *ifp, struct net_port_info *npi,
1280 uint32_t pkt_total_len, uint32_t pkt_data_len, uint16_t pkt_control_flags)
1281{
1282 struct kev_msg ev_msg = {};
1283
1284 ev_msg.vendor_code = KEV_VENDOR_APPLE;
1285 ev_msg.kev_class = KEV_NETWORK_CLASS;
1286 ev_msg.kev_subclass = KEV_POWER_SUBCLASS;
1287 ev_msg.event_code = KEV_POWER_WAKE_PACKET;
1288
1289 struct net_port_info_wake_event event_data = {};
1290
1291 uuid_copy(dst: event_data.wake_uuid, src: current_wakeuuid);
1292 event_data.wake_pkt_if_index = ifp->if_index;
1293 event_data.wake_pkt_port = npi->npi_local_port;
1294 event_data.wake_pkt_flags = npi->npi_flags;
1295 event_data.wake_pkt_owner_pid = npi->npi_owner_pid;
1296 event_data.wake_pkt_effective_pid = npi->npi_effective_pid;
1297 strlcpy(dst: event_data.wake_pkt_owner_pname, src: npi->npi_owner_pname,
1298 n: sizeof(event_data.wake_pkt_owner_pname));
1299 strlcpy(dst: event_data.wake_pkt_effective_pname, src: npi->npi_effective_pname,
1300 n: sizeof(event_data.wake_pkt_effective_pname));
1301 uuid_copy(dst: event_data.wake_pkt_owner_uuid, src: npi->npi_owner_uuid);
1302 uuid_copy(dst: event_data.wake_pkt_effective_uuid, src: npi->npi_effective_uuid);
1303
1304 event_data.wake_pkt_foreign_port = npi->npi_foreign_port;
1305 event_data.wake_pkt_local_addr_ = npi->npi_local_addr_;
1306 event_data.wake_pkt_foreign_addr_ = npi->npi_foreign_addr_;
1307 strlcpy(dst: event_data.wake_pkt_ifname, IF_XNAME(ifp), n: sizeof(event_data.wake_pkt_ifname));
1308
1309 event_data.wake_pkt_if_info.npi_if_family = ifp->if_family;
1310 event_data.wake_pkt_if_info.npi_if_subfamily = ifp->if_subfamily;
1311 event_data.wake_pkt_if_info.npi_if_functional_type = if_functional_type(ifp, true);
1312
1313 strlcpy(dst: event_data.wake_pkt_phy_ifname, src: last_wake_phy_if_name,
1314 n: sizeof(event_data.wake_pkt_phy_ifname));
1315 event_data.wake_pkt_phy_if_info.npi_if_family = last_wake_phy_if_family;
1316 event_data.wake_pkt_phy_if_info.npi_if_subfamily = last_wake_phy_if_subfamily;
1317 event_data.wake_pkt_phy_if_info.npi_if_functional_type = last_wake_phy_if_functional_type;
1318
1319 event_data.wake_pkt_total_len = pkt_total_len;
1320 event_data.wake_pkt_data_len = pkt_data_len;
1321 event_data.wake_pkt_control_flags = pkt_control_flags;
1322 if (npi->npi_flags & NPIF_NOWAKE) {
1323 event_data.wake_pkt_control_flags |= NPICF_NOWAKE;
1324 }
1325
1326 ev_msg.dv[0].data_ptr = &event_data;
1327 ev_msg.dv[0].data_length = sizeof(event_data);
1328
1329 LCK_MTX_ASSERT(&net_port_entry_head_lock, LCK_MTX_ASSERT_NOTOWNED);
1330
1331 lck_mtx_lock(lck: &net_port_entry_head_lock);
1332
1333 if (has_notified_wake_pkt) {
1334 lck_mtx_unlock(lck: &net_port_entry_head_lock);
1335 if_ports_used_stats.ifpu_dup_wake_pkt_event += 1;
1336
1337 if (__improbable(net_wake_pkt_debug > 0)) {
1338 net_port_info_log_npi(s: "already notified wake packet", npi);
1339 }
1340 return;
1341 }
1342 has_notified_wake_pkt = true;
1343
1344 memcpy(dst: &last_attributed_wake_event, src: &event_data, n: sizeof(last_attributed_wake_event));
1345
1346 lck_mtx_unlock(lck: &net_port_entry_head_lock);
1347
1348 if (npi->npi_flags & NPIF_NOWAKE) {
1349 if_ports_used_stats.ifpu_spurious_wake_event += 1;
1350 } else {
1351 if_ports_used_stats.ifpu_wake_pkt_event += 1;
1352 }
1353
1354 int result = kev_post_msg(event: &ev_msg);
1355 if (result != 0) {
1356 uuid_string_t wake_uuid_str;
1357
1358 uuid_unparse(uu: event_data.wake_uuid, out: wake_uuid_str);
1359 os_log_error(OS_LOG_DEFAULT,
1360 "%s: kev_post_msg() failed with error %d for wake uuid %s",
1361 __func__, result, wake_uuid_str);
1362
1363 if_ports_used_stats.ifpu_wake_pkt_event_error += 1;
1364 }
1365#if (DEBUG || DEVELOPMENT)
1366 net_port_info_log_wake_event("attributed wake packet event", &event_data);
1367#endif /* (DEBUG || DEVELOPMENT) */
1368}
1369
1370static bool
1371is_encapsulated_esp(struct mbuf *m, size_t data_offset)
1372{
1373 /*
1374 * They are three cases:
1375 * - Keep alive: 1 byte payload
1376 * - IKE: payload start with 4 bytes header set to zero before ISAKMP header
1377 * - otherwise it's ESP
1378 */
1379 ASSERT(m->m_pkthdr.len >= data_offset);
1380
1381 size_t data_len = m->m_pkthdr.len - data_offset;
1382 if (data_len == 1) {
1383 return false;
1384 } else if (data_len > ESP_HDR_SIZE) {
1385 uint8_t payload[ESP_HDR_SIZE];
1386
1387 errno_t error = mbuf_copydata(mbuf: m, offset: data_offset, ESP_HDR_SIZE, out_data: &payload);
1388 if (error != 0) {
1389 os_log(OS_LOG_DEFAULT, "%s: mbuf_copydata(ESP_HDR_SIZE) error %d",
1390 __func__, error);
1391 } else if (payload[0] == 0 && payload[1] == 0 &&
1392 payload[2] == 0 && payload[3] == 0) {
1393 return false;
1394 }
1395 }
1396 return true;
1397}
1398
1399void
1400if_ports_used_match_mbuf(struct ifnet *ifp, protocol_family_t proto_family, struct mbuf *m)
1401{
1402 errno_t error;
1403 struct net_port_info npi = {};
1404 bool found = false;
1405 uint32_t pkt_total_len = 0;
1406 uint32_t pkt_data_len = 0;
1407 uint16_t pkt_control_flags = 0;
1408 uint16_t pkt_proto = 0;
1409
1410 if ((m->m_pkthdr.pkt_flags & PKTF_WAKE_PKT) == 0) {
1411 if_ports_used_stats.ifpu_match_wake_pkt_no_flag += 1;
1412 os_log_error(OS_LOG_DEFAULT, "%s: called PKTF_WAKE_PKT not set from %s",
1413 __func__, ifp != NULL ? IF_XNAME(ifp) : "");
1414 return;
1415 }
1416
1417 if_ports_used_stats.ifpu_so_match_wake_pkt += 1;
1418 npi.npi_flags |= NPIF_SOCKET; /* For logging */
1419 pkt_total_len = m->m_pkthdr.len;
1420 pkt_data_len = pkt_total_len;
1421
1422 if (ifp != NULL) {
1423 npi.npi_if_index = ifp->if_index;
1424 if (IFNET_IS_COMPANION_LINK(ifp)) {
1425 npi.npi_flags |= NPIF_COMPLINK;
1426 }
1427 if_set_wake_physical_interface(ifp);
1428 }
1429
1430 if (proto_family == PF_INET) {
1431 struct ip iphdr = {};
1432
1433 if_ports_used_stats.ifpu_ipv4_wake_pkt += 1;
1434
1435 error = mbuf_copydata(mbuf: m, offset: 0, length: sizeof(struct ip), out_data: &iphdr);
1436 if (error != 0) {
1437 os_log(OS_LOG_DEFAULT, "%s: mbuf_copydata(ip) error %d",
1438 __func__, error);
1439 goto failed;
1440 }
1441 npi.npi_flags |= NPIF_IPV4;
1442 npi.npi_local_addr_in = iphdr.ip_dst;
1443 npi.npi_foreign_addr_in = iphdr.ip_src;
1444
1445 /*
1446 * Check if this is a fragment that is not the first fragment
1447 */
1448 if ((ntohs(iphdr.ip_off) & ~(IP_DF | IP_RF)) &&
1449 (ntohs(iphdr.ip_off) & IP_OFFMASK) != 0) {
1450 npi.npi_flags |= NPIF_FRAG;
1451 if_ports_used_stats.ifpu_frag_wake_pkt += 1;
1452 }
1453
1454 if ((iphdr.ip_hl << 2) < pkt_data_len) {
1455 pkt_data_len -= iphdr.ip_hl << 2;
1456 } else {
1457 pkt_data_len = 0;
1458 }
1459
1460 pkt_proto = iphdr.ip_p;
1461
1462 switch (iphdr.ip_p) {
1463 case IPPROTO_TCP: {
1464 if_ports_used_stats.ifpu_tcp_wake_pkt += 1;
1465 npi.npi_flags |= NPIF_TCP;
1466
1467 if (npi.npi_flags & NPIF_FRAG) {
1468 goto failed;
1469 }
1470
1471 struct tcphdr th = {};
1472 error = mbuf_copydata(mbuf: m, offset: iphdr.ip_hl << 2, length: sizeof(struct tcphdr), out_data: &th);
1473 if (error != 0) {
1474 os_log(OS_LOG_DEFAULT, "%s: mbuf_copydata(tcphdr) error %d",
1475 __func__, error);
1476 goto failed;
1477 }
1478 npi.npi_local_port = th.th_dport;
1479 npi.npi_foreign_port = th.th_sport;
1480
1481 if (pkt_data_len < sizeof(struct tcphdr) ||
1482 pkt_data_len < (th.th_off << 2)) {
1483 pkt_data_len = 0;
1484 } else {
1485 pkt_data_len -= th.th_off << 2;
1486 }
1487 pkt_control_flags = th.th_flags;
1488 break;
1489 }
1490 case IPPROTO_UDP: {
1491 if_ports_used_stats.ifpu_udp_wake_pkt += 1;
1492 npi.npi_flags |= NPIF_UDP;
1493
1494 if (npi.npi_flags & NPIF_FRAG) {
1495 goto failed;
1496 }
1497 struct udphdr uh = {};
1498 size_t udp_offset = iphdr.ip_hl << 2;
1499
1500 error = mbuf_copydata(mbuf: m, offset: udp_offset, length: sizeof(struct udphdr), out_data: &uh);
1501 if (error != 0) {
1502 os_log(OS_LOG_DEFAULT, "%s: mbuf_copydata(udphdr) error %d",
1503 __func__, error);
1504 goto failed;
1505 }
1506 npi.npi_local_port = uh.uh_dport;
1507 npi.npi_foreign_port = uh.uh_sport;
1508 /*
1509 * Let the ESP layer handle wake packets
1510 */
1511 if (ntohs(uh.uh_dport) == PORT_ISAKMP_NATT ||
1512 ntohs(uh.uh_sport) == PORT_ISAKMP_NATT) {
1513 if_ports_used_stats.ifpu_isakmp_natt_wake_pkt += 1;
1514 if (is_encapsulated_esp(m, data_offset: udp_offset + sizeof(struct udphdr))) {
1515 if (net_wake_pkt_debug > 0) {
1516 net_port_info_log_npi(s: "defer ISAKMP_NATT matching", npi: &npi);
1517 }
1518 return;
1519 }
1520 }
1521
1522 if (pkt_data_len < sizeof(struct udphdr)) {
1523 pkt_data_len = 0;
1524 } else {
1525 pkt_data_len -= sizeof(struct udphdr);
1526 }
1527 break;
1528 }
1529 case IPPROTO_ESP: {
1530 /*
1531 * Let the ESP layer handle wake packets
1532 */
1533 if_ports_used_stats.ifpu_esp_wake_pkt += 1;
1534 npi.npi_flags |= NPIF_ESP;
1535 if (net_wake_pkt_debug > 0) {
1536 net_port_info_log_npi(s: "defer ESP matching", npi: &npi);
1537 }
1538 return;
1539 }
1540 default:
1541 if_ports_used_stats.ifpu_bad_proto_wake_pkt += 1;
1542 os_log(OS_LOG_DEFAULT, "%s: unexpected IPv4 protocol %u from %s",
1543 __func__, iphdr.ip_p, IF_XNAME(ifp));
1544 goto failed;
1545 }
1546 } else if (proto_family == PF_INET6) {
1547 struct ip6_hdr ip6_hdr = {};
1548
1549 if_ports_used_stats.ifpu_ipv6_wake_pkt += 1;
1550
1551 error = mbuf_copydata(mbuf: m, offset: 0, length: sizeof(struct ip6_hdr), out_data: &ip6_hdr);
1552 if (error != 0) {
1553 os_log(OS_LOG_DEFAULT, "%s: mbuf_copydata(ip6_hdr) error %d",
1554 __func__, error);
1555 goto failed;
1556 }
1557 npi.npi_flags |= NPIF_IPV6;
1558 memcpy(dst: &npi.npi_local_addr_in6, src: &ip6_hdr.ip6_dst, n: sizeof(struct in6_addr));
1559 memcpy(dst: &npi.npi_foreign_addr_in6, src: &ip6_hdr.ip6_src, n: sizeof(struct in6_addr));
1560
1561 size_t l3_len = sizeof(struct ip6_hdr);
1562 uint8_t l4_proto = ip6_hdr.ip6_nxt;
1563
1564 pkt_proto = l4_proto;
1565
1566 if (pkt_data_len < l3_len) {
1567 pkt_data_len = 0;
1568 } else {
1569 pkt_data_len -= l3_len;
1570 }
1571
1572 /*
1573 * Check if this is a fragment that is not the first fragment
1574 */
1575 if (l4_proto == IPPROTO_FRAGMENT) {
1576 struct ip6_frag ip6_frag;
1577
1578 error = mbuf_copydata(mbuf: m, offset: sizeof(struct ip6_hdr), length: sizeof(struct ip6_frag), out_data: &ip6_frag);
1579 if (error != 0) {
1580 os_log(OS_LOG_DEFAULT, "%s: mbuf_copydata(ip6_frag) error %d",
1581 __func__, error);
1582 goto failed;
1583 }
1584
1585 l3_len += sizeof(struct ip6_frag);
1586 l4_proto = ip6_frag.ip6f_nxt;
1587
1588 if ((ip6_frag.ip6f_offlg & IP6F_OFF_MASK) != 0) {
1589 npi.npi_flags |= NPIF_FRAG;
1590 if_ports_used_stats.ifpu_frag_wake_pkt += 1;
1591 }
1592 }
1593
1594
1595 switch (l4_proto) {
1596 case IPPROTO_TCP: {
1597 if_ports_used_stats.ifpu_tcp_wake_pkt += 1;
1598 npi.npi_flags |= NPIF_TCP;
1599
1600 /*
1601 * Cannot attribute a fragment that is not the first fragment as it
1602 * not have the TCP header
1603 */
1604 if (npi.npi_flags & NPIF_FRAG) {
1605 goto failed;
1606 }
1607
1608 struct tcphdr th = {};
1609
1610 error = mbuf_copydata(mbuf: m, offset: l3_len, length: sizeof(struct tcphdr), out_data: &th);
1611 if (error != 0) {
1612 os_log(OS_LOG_DEFAULT, "%s: mbuf_copydata(tcphdr) error %d",
1613 __func__, error);
1614 if_ports_used_stats.ifpu_incomplete_tcp_hdr_pkt += 1;
1615 goto failed;
1616 }
1617 npi.npi_local_port = th.th_dport;
1618 npi.npi_foreign_port = th.th_sport;
1619
1620 if (pkt_data_len < sizeof(struct tcphdr) ||
1621 pkt_data_len < (th.th_off << 2)) {
1622 pkt_data_len = 0;
1623 } else {
1624 pkt_data_len -= th.th_off << 2;
1625 }
1626 pkt_control_flags = th.th_flags;
1627 break;
1628 }
1629 case IPPROTO_UDP: {
1630 if_ports_used_stats.ifpu_udp_wake_pkt += 1;
1631 npi.npi_flags |= NPIF_UDP;
1632
1633 /*
1634 * Cannot attribute a fragment that is not the first fragment as it
1635 * not have the UDP header
1636 */
1637 if (npi.npi_flags & NPIF_FRAG) {
1638 goto failed;
1639 }
1640
1641 struct udphdr uh = {};
1642
1643 error = mbuf_copydata(mbuf: m, offset: l3_len, length: sizeof(struct udphdr), out_data: &uh);
1644 if (error != 0) {
1645 os_log(OS_LOG_DEFAULT, "%s: mbuf_copydata(udphdr) error %d",
1646 __func__, error);
1647 if_ports_used_stats.ifpu_incomplete_udp_hdr_pkt += 1;
1648 goto failed;
1649 }
1650 npi.npi_local_port = uh.uh_dport;
1651 npi.npi_foreign_port = uh.uh_sport;
1652 /*
1653 * Let the ESP layer handle wake packets
1654 */
1655 if (ntohs(npi.npi_local_port) == PORT_ISAKMP_NATT ||
1656 ntohs(npi.npi_foreign_port) == PORT_ISAKMP_NATT) {
1657 if_ports_used_stats.ifpu_isakmp_natt_wake_pkt += 1;
1658 if (is_encapsulated_esp(m, data_offset: l3_len + sizeof(struct udphdr))) {
1659 if (net_wake_pkt_debug > 0) {
1660 net_port_info_log_npi(s: "defer encapsulated ESP matching", npi: &npi);
1661 }
1662 return;
1663 }
1664 }
1665
1666 if (pkt_data_len < sizeof(struct udphdr)) {
1667 pkt_data_len = 0;
1668 } else {
1669 pkt_data_len -= sizeof(struct udphdr);
1670 }
1671 break;
1672 }
1673 case IPPROTO_ESP: {
1674 /*
1675 * Let the ESP layer handle the wake packet
1676 */
1677 if_ports_used_stats.ifpu_esp_wake_pkt += 1;
1678 npi.npi_flags |= NPIF_ESP;
1679 if (net_wake_pkt_debug > 0) {
1680 net_port_info_log_npi(s: "defer ESP matching", npi: &npi);
1681 }
1682 return;
1683 }
1684 default:
1685 if_ports_used_stats.ifpu_bad_proto_wake_pkt += 1;
1686
1687 os_log(OS_LOG_DEFAULT, "%s: unexpected IPv6 protocol %u from %s",
1688 __func__, ip6_hdr.ip6_nxt, IF_XNAME(ifp));
1689 goto failed;
1690 }
1691 } else {
1692 if_ports_used_stats.ifpu_bad_family_wake_pkt += 1;
1693 os_log(OS_LOG_DEFAULT, "%s: unexpected protocol family %d from %s",
1694 __func__, proto_family, IF_XNAME(ifp));
1695 goto failed;
1696 }
1697 if (ifp == NULL) {
1698 goto failed;
1699 }
1700
1701 found = net_port_info_find_match(in_npi: &npi);
1702 if (found) {
1703 if_notify_wake_packet(ifp, npi: &npi,
1704 pkt_total_len, pkt_data_len, pkt_control_flags);
1705 } else {
1706 if_notify_unattributed_wake_mbuf(ifp, m, npi: &npi,
1707 pkt_total_len, pkt_data_len, pkt_control_flags, proto: pkt_proto);
1708 }
1709 return;
1710failed:
1711 if_notify_unattributed_wake_mbuf(ifp, m, npi: &npi,
1712 pkt_total_len, pkt_data_len, pkt_control_flags, proto: pkt_proto);
1713}
1714
1715#if SKYWALK
1716
1717static void
1718if_notify_unattributed_wake_pkt(struct ifnet *ifp, struct __kern_packet *pkt,
1719 struct net_port_info *npi, uint32_t pkt_total_len, uint32_t pkt_data_len,
1720 uint16_t pkt_control_flags, uint16_t proto)
1721{
1722 struct kev_msg ev_msg = {};
1723
1724 LCK_MTX_ASSERT(&net_port_entry_head_lock, LCK_MTX_ASSERT_NOTOWNED);
1725
1726 lck_mtx_lock(lck: &net_port_entry_head_lock);
1727 if (has_notified_unattributed_wake) {
1728 lck_mtx_unlock(lck: &net_port_entry_head_lock);
1729 if_ports_used_stats.ifpu_dup_unattributed_wake_event += 1;
1730
1731 if (__improbable(net_wake_pkt_debug > 0)) {
1732 net_port_info_log_npi(s: "already notified unattributed wake packet", npi);
1733 }
1734 return;
1735 }
1736 has_notified_unattributed_wake = true;
1737 lck_mtx_unlock(lck: &net_port_entry_head_lock);
1738
1739 if_ports_used_stats.ifpu_unattributed_wake_event += 1;
1740
1741 if (ifp == NULL) {
1742 os_log(OS_LOG_DEFAULT, "%s: receive interface is NULL",
1743 __func__);
1744 if_ports_used_stats.ifpu_unattributed_null_recvif += 1;
1745 }
1746
1747 ev_msg.vendor_code = KEV_VENDOR_APPLE;
1748 ev_msg.kev_class = KEV_NETWORK_CLASS;
1749 ev_msg.kev_subclass = KEV_POWER_SUBCLASS;
1750 ev_msg.event_code = KEV_POWER_UNATTRIBUTED_WAKE;
1751
1752 struct net_port_info_una_wake_event event_data = {};
1753 uuid_copy(dst: event_data.una_wake_uuid, src: current_wakeuuid);
1754 event_data.una_wake_pkt_if_index = ifp != NULL ? ifp->if_index : 0;
1755 event_data.una_wake_pkt_flags = npi->npi_flags;
1756
1757 uint16_t offset = kern_packet_get_network_header_offset(SK_PKT2PH(pkt));
1758 event_data.una_wake_ptk_len =
1759 pkt->pkt_length - offset > NPI_MAX_UNA_WAKE_PKT_LEN ?
1760 NPI_MAX_UNA_WAKE_PKT_LEN : (u_int16_t) pkt->pkt_length - offset;
1761
1762 kern_packet_copy_bytes(SK_PKT2PH(pkt), offset, event_data.una_wake_ptk_len,
1763 event_data.una_wake_pkt);
1764
1765 event_data.una_wake_pkt_local_port = npi->npi_local_port;
1766 event_data.una_wake_pkt_foreign_port = npi->npi_foreign_port;
1767 event_data.una_wake_pkt_local_addr_ = npi->npi_local_addr_;
1768 event_data.una_wake_pkt_foreign_addr_ = npi->npi_foreign_addr_;
1769 if (ifp != NULL) {
1770 strlcpy(dst: event_data.una_wake_pkt_ifname, IF_XNAME(ifp),
1771 n: sizeof(event_data.una_wake_pkt_ifname));
1772 }
1773
1774 event_data.una_wake_pkt_total_len = pkt_total_len;
1775 event_data.una_wake_pkt_data_len = pkt_data_len;
1776 event_data.una_wake_pkt_control_flags = pkt_control_flags;
1777 event_data.una_wake_pkt_proto = proto;
1778
1779 ev_msg.dv[0].data_ptr = &event_data;
1780 ev_msg.dv[0].data_length = sizeof(event_data);
1781
1782 int result = kev_post_msg(event: &ev_msg);
1783 if (result != 0) {
1784 uuid_string_t wake_uuid_str;
1785
1786 uuid_unparse(uu: event_data.una_wake_uuid, out: wake_uuid_str);
1787 os_log_error(OS_LOG_DEFAULT,
1788 "%s: kev_post_msg() failed with error %d for wake uuid %s",
1789 __func__, result, wake_uuid_str);
1790
1791 if_ports_used_stats.ifpu_unattributed_wake_event_error += 1;
1792 }
1793#if (DEBUG || DEVELOPMENT)
1794 net_port_info_log_una_wake_event("unattributed wake packet event", &event_data);
1795#endif /* (DEBUG || DEVELOPMENT) */
1796}
1797
1798void
1799if_ports_used_match_pkt(struct ifnet *ifp, struct __kern_packet *pkt)
1800{
1801 struct net_port_info npi = {};
1802 bool found = false;
1803 uint32_t pkt_total_len = 0;
1804 uint32_t pkt_data_len = 0;
1805 uint16_t pkt_control_flags = 0;
1806 uint16_t pkt_proto = 0;
1807
1808 if ((pkt->pkt_pflags & PKT_F_WAKE_PKT) == 0) {
1809 if_ports_used_stats.ifpu_match_wake_pkt_no_flag += 1;
1810 os_log_error(OS_LOG_DEFAULT, "%s: called PKT_F_WAKE_PKT not set from %s",
1811 __func__, IF_XNAME(ifp));
1812 return;
1813 }
1814
1815 if_ports_used_stats.ifpu_ch_match_wake_pkt += 1;
1816 npi.npi_flags |= NPIF_CHANNEL; /* For logging */
1817 pkt_total_len = pkt->pkt_flow_ip_hlen +
1818 pkt->pkt_flow_tcp_hlen + pkt->pkt_flow_ulen;
1819 pkt_data_len = pkt->pkt_flow_ulen;
1820
1821 if (ifp != NULL) {
1822 npi.npi_if_index = ifp->if_index;
1823 if (IFNET_IS_COMPANION_LINK(ifp)) {
1824 npi.npi_flags |= NPIF_COMPLINK;
1825 }
1826 if_set_wake_physical_interface(ifp);
1827 }
1828
1829 switch (pkt->pkt_flow_ip_ver) {
1830 case IPVERSION:
1831 if_ports_used_stats.ifpu_ipv4_wake_pkt += 1;
1832
1833 npi.npi_flags |= NPIF_IPV4;
1834 npi.npi_local_addr_in = pkt->pkt_flow_ipv4_dst;
1835 npi.npi_foreign_addr_in = pkt->pkt_flow_ipv4_src;
1836 break;
1837 case IPV6_VERSION:
1838 if_ports_used_stats.ifpu_ipv6_wake_pkt += 1;
1839
1840 npi.npi_flags |= NPIF_IPV6;
1841 memcpy(dst: &npi.npi_local_addr_in6, src: &pkt->pkt_flow_ipv6_dst,
1842 n: sizeof(struct in6_addr));
1843 memcpy(dst: &npi.npi_foreign_addr_in6, src: &pkt->pkt_flow_ipv6_src,
1844 n: sizeof(struct in6_addr));
1845 break;
1846 default:
1847 if_ports_used_stats.ifpu_bad_family_wake_pkt += 1;
1848
1849 os_log(OS_LOG_DEFAULT, "%s: unexpected protocol family %u from %s",
1850 __func__, pkt->pkt_flow_ip_ver, IF_XNAME(ifp));
1851 goto failed;
1852 }
1853 pkt_proto = pkt->pkt_flow_ip_ver;
1854
1855 /*
1856 * Check if this is a fragment that is not the first fragment
1857 */
1858 if (pkt->pkt_flow_ip_is_frag && !pkt->pkt_flow_ip_is_first_frag) {
1859 os_log(OS_LOG_DEFAULT, "%s: unexpected wake fragment from %s",
1860 __func__, IF_XNAME(ifp));
1861 npi.npi_flags |= NPIF_FRAG;
1862 if_ports_used_stats.ifpu_frag_wake_pkt += 1;
1863 }
1864
1865 switch (pkt->pkt_flow_ip_proto) {
1866 case IPPROTO_TCP: {
1867 if_ports_used_stats.ifpu_tcp_wake_pkt += 1;
1868 npi.npi_flags |= NPIF_TCP;
1869
1870 /*
1871 * Cannot attribute a fragment that is not the first fragment as it
1872 * not have the TCP header
1873 */
1874 if (npi.npi_flags & NPIF_FRAG) {
1875 goto failed;
1876 }
1877 struct tcphdr *tcp = (struct tcphdr *)pkt->pkt_flow_tcp_hdr;
1878 if (tcp == NULL) {
1879 os_log(OS_LOG_DEFAULT, "%s: pkt with unassigned TCP header from %s",
1880 __func__, IF_XNAME(ifp));
1881 if_ports_used_stats.ifpu_incomplete_tcp_hdr_pkt += 1;
1882 goto failed;
1883 }
1884 npi.npi_local_port = tcp->th_dport;
1885 npi.npi_foreign_port = tcp->th_sport;
1886 pkt_control_flags = tcp->th_flags;
1887 break;
1888 }
1889 case IPPROTO_UDP: {
1890 if_ports_used_stats.ifpu_udp_wake_pkt += 1;
1891 npi.npi_flags |= NPIF_UDP;
1892
1893 /*
1894 * Cannot attribute a fragment that is not the first fragment as it
1895 * not have the UDP header
1896 */
1897 if (npi.npi_flags & NPIF_FRAG) {
1898 goto failed;
1899 }
1900 struct udphdr *uh = (struct udphdr *)pkt->pkt_flow_udp_hdr;
1901 if (uh == NULL) {
1902 os_log(OS_LOG_DEFAULT, "%s: pkt with unassigned UDP header from %s",
1903 __func__, IF_XNAME(ifp));
1904 if_ports_used_stats.ifpu_incomplete_udp_hdr_pkt += 1;
1905 goto failed;
1906 }
1907 npi.npi_local_port = uh->uh_dport;
1908 npi.npi_foreign_port = uh->uh_sport;
1909
1910 /*
1911 * Defer matching of UDP NAT traversal to ip_input
1912 * (assumes IKE uses sockets)
1913 */
1914 if (ntohs(npi.npi_local_port) == PORT_ISAKMP_NATT ||
1915 ntohs(npi.npi_foreign_port) == PORT_ISAKMP_NATT) {
1916 if_ports_used_stats.ifpu_deferred_isakmp_natt_wake_pkt += 1;
1917 if (net_wake_pkt_debug > 0) {
1918 net_port_info_log_npi(s: "defer ISAKMP_NATT matching", npi: &npi);
1919 }
1920 return;
1921 }
1922 break;
1923 }
1924 case IPPROTO_ESP: {
1925 /*
1926 * Let the ESP layer handle the wake packet
1927 */
1928 if_ports_used_stats.ifpu_esp_wake_pkt += 1;
1929 npi.npi_flags |= NPIF_ESP;
1930 if (net_wake_pkt_debug > 0) {
1931 net_port_info_log_npi(s: "defer ESP matching", npi: &npi);
1932 }
1933 return;
1934 }
1935 default:
1936 if_ports_used_stats.ifpu_bad_proto_wake_pkt += 1;
1937
1938 os_log(OS_LOG_DEFAULT, "%s: unexpected IP protocol %u from %s",
1939 __func__, pkt->pkt_flow_ip_proto, IF_XNAME(ifp));
1940 goto failed;
1941 }
1942
1943 if (ifp == NULL) {
1944 goto failed;
1945 }
1946
1947 found = net_port_info_find_match(in_npi: &npi);
1948 if (found) {
1949 if_notify_wake_packet(ifp, npi: &npi,
1950 pkt_total_len, pkt_data_len, pkt_control_flags);
1951 } else {
1952 if_notify_unattributed_wake_pkt(ifp, pkt, npi: &npi,
1953 pkt_total_len, pkt_data_len, pkt_control_flags, proto: pkt_proto);
1954 }
1955 return;
1956failed:
1957 if_notify_unattributed_wake_pkt(ifp, pkt, npi: &npi,
1958 pkt_total_len, pkt_data_len, pkt_control_flags, proto: pkt_proto);
1959}
1960#endif /* SKYWALK */
1961
1962int
1963sysctl_last_attributed_wake_event SYSCTL_HANDLER_ARGS
1964{
1965#pragma unused(oidp, arg1, arg2)
1966 size_t len = sizeof(struct net_port_info_wake_event);
1967
1968 if (req->oldptr != 0) {
1969 len = MIN(req->oldlen, len);
1970 }
1971 lck_mtx_lock(lck: &net_port_entry_head_lock);
1972 int error = SYSCTL_OUT(req, &last_attributed_wake_event, len);
1973 lck_mtx_unlock(lck: &net_port_entry_head_lock);
1974
1975 return error;
1976}
1977