]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/in_tclass.c
xnu-4903.270.47.tar.gz
[apple/xnu.git] / bsd / netinet / in_tclass.c
1 /*
2 * Copyright (c) 2009-2019 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/systm.h>
30 #include <sys/kernel.h>
31 #include <sys/types.h>
32 #include <sys/filedesc.h>
33 #include <sys/file_internal.h>
34 #include <sys/proc.h>
35 #include <sys/socket.h>
36 #include <sys/socketvar.h>
37 #include <sys/errno.h>
38 #include <sys/protosw.h>
39 #include <sys/domain.h>
40 #include <sys/mbuf.h>
41 #include <sys/queue.h>
42 #include <sys/sysctl.h>
43 #include <sys/sysproto.h>
44
45 #include <net/if.h>
46 #include <net/if_var.h>
47 #include <net/route.h>
48
49 #include <netinet/in.h>
50 #include <netinet/in_var.h>
51 #include <netinet/in_pcb.h>
52 #include <netinet/ip.h>
53 #include <netinet/ip_var.h>
54 #include <netinet/ip6.h>
55 #include <netinet6/ip6_var.h>
56 #include <netinet/udp.h>
57 #include <netinet/udp_var.h>
58 #include <netinet/tcp.h>
59 #include <netinet/tcp_var.h>
60 #include <netinet/tcp_cc.h>
61 #include <netinet/lro_ext.h>
62 #include <netinet/in_tclass.h>
63
64 struct dcsp_msc_map {
65 u_int8_t dscp;
66 mbuf_svc_class_t msc;
67 };
68 static inline int so_throttle_best_effort(struct socket *, struct ifnet *);
69 static void set_dscp_to_wifi_ac_map(const struct dcsp_msc_map *, int);
70 static errno_t dscp_msc_map_from_netsvctype_dscp_map(struct netsvctype_dscp_map *, size_t,
71 struct dcsp_msc_map *);
72
73 static lck_grp_attr_t *tclass_lck_grp_attr = NULL; /* mutex group attributes */
74 static lck_grp_t *tclass_lck_grp = NULL; /* mutex group definition */
75 static lck_attr_t *tclass_lck_attr = NULL; /* mutex attributes */
76 decl_lck_mtx_data(static, tclass_lock_data);
77 static lck_mtx_t *tclass_lock = &tclass_lock_data;
78
79 SYSCTL_NODE(_net, OID_AUTO, qos,
80 CTLFLAG_RW | CTLFLAG_LOCKED, 0, "QoS");
81
82 static int sysctl_default_netsvctype_to_dscp_map SYSCTL_HANDLER_ARGS;
83 SYSCTL_PROC(_net_qos, OID_AUTO, default_netsvctype_to_dscp_map,
84 CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_LOCKED,
85 0, 0, sysctl_default_netsvctype_to_dscp_map, "S", "");
86
87 static int sysctl_dscp_to_wifi_ac_map SYSCTL_HANDLER_ARGS;
88 SYSCTL_PROC(_net_qos, OID_AUTO, dscp_to_wifi_ac_map,
89 CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_LOCKED,
90 0, 0, sysctl_dscp_to_wifi_ac_map, "S", "");
91
92 static int sysctl_reset_dscp_to_wifi_ac_map SYSCTL_HANDLER_ARGS;
93 SYSCTL_PROC(_net_qos, OID_AUTO, reset_dscp_to_wifi_ac_map,
94 CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_LOCKED,
95 0, 0, sysctl_reset_dscp_to_wifi_ac_map, "I", "");
96
97 int net_qos_verbose = 0;
98 SYSCTL_INT(_net_qos, OID_AUTO, verbose,
99 CTLFLAG_RW | CTLFLAG_LOCKED, &net_qos_verbose, 0, "");
100
101 /*
102 * Fastlane QoS policy:
103 * By Default allow all apps to get traffic class to DSCP mapping
104 */
105 SYSCTL_NODE(_net_qos, OID_AUTO, policy,
106 CTLFLAG_RW | CTLFLAG_LOCKED, 0, "");
107
108 int net_qos_policy_restricted = 0;
109 SYSCTL_INT(_net_qos_policy, OID_AUTO, restricted,
110 CTLFLAG_RW | CTLFLAG_LOCKED, &net_qos_policy_restricted, 0, "");
111
112 int net_qos_policy_restrict_avapps = 0;
113 SYSCTL_INT(_net_qos_policy, OID_AUTO, restrict_avapps,
114 CTLFLAG_RW | CTLFLAG_LOCKED, &net_qos_policy_restrict_avapps, 0, "");
115
116 int net_qos_policy_wifi_enabled = 0;
117 SYSCTL_INT(_net_qos_policy, OID_AUTO, wifi_enabled,
118 CTLFLAG_RW | CTLFLAG_LOCKED, &net_qos_policy_wifi_enabled, 0, "");
119
120 int net_qos_policy_none_wifi_enabled = 0;
121 SYSCTL_INT(_net_qos_policy, OID_AUTO, none_wifi_enabled,
122 CTLFLAG_RW | CTLFLAG_LOCKED, &net_qos_policy_none_wifi_enabled, 0, "");
123
124 int net_qos_policy_capable_enabled = 0;
125 SYSCTL_INT(_net_qos_policy, OID_AUTO, capable_enabled,
126 CTLFLAG_RW | CTLFLAG_LOCKED, &net_qos_policy_capable_enabled, 0, "");
127
128 /*
129 * Socket traffic class from network service type
130 */
131 const int sotc_by_netservicetype[_NET_SERVICE_TYPE_COUNT] = {
132 SO_TC_BE, /* NET_SERVICE_TYPE_BE */
133 SO_TC_BK_SYS, /* NET_SERVICE_TYPE_BK */
134 SO_TC_VI, /* NET_SERVICE_TYPE_SIG */
135 SO_TC_VI, /* NET_SERVICE_TYPE_VI */
136 SO_TC_VO, /* NET_SERVICE_TYPE_VO */
137 SO_TC_RV, /* NET_SERVICE_TYPE_RV */
138 SO_TC_AV, /* NET_SERVICE_TYPE_AV */
139 SO_TC_OAM, /* NET_SERVICE_TYPE_OAM */
140 SO_TC_RD /* NET_SERVICE_TYPE_RD */
141 };
142
143 /*
144 * DSCP mappings for QoS Fastlane as based on network service types
145 */
146 static const
147 struct netsvctype_dscp_map fastlane_netsvctype_dscp_map[_NET_SERVICE_TYPE_COUNT] = {
148 { NET_SERVICE_TYPE_BE, _DSCP_DF },
149 { NET_SERVICE_TYPE_BK, _DSCP_AF11 },
150 { NET_SERVICE_TYPE_SIG, _DSCP_CS3 },
151 { NET_SERVICE_TYPE_VI, _DSCP_AF41 },
152 { NET_SERVICE_TYPE_VO, _DSCP_EF },
153 { NET_SERVICE_TYPE_RV, _DSCP_CS4 },
154 { NET_SERVICE_TYPE_AV, _DSCP_AF31 },
155 { NET_SERVICE_TYPE_OAM, _DSCP_CS2 },
156 { NET_SERVICE_TYPE_RD, _DSCP_AF21 },
157 };
158
159 static struct net_qos_dscp_map default_net_qos_dscp_map;
160
161 /*
162 * The size is one more than the max because DSCP start at zero
163 */
164 #define DSCP_ARRAY_SIZE (_MAX_DSCP + 1)
165
166 /*
167 * The DSCP to UP mapping (via mbuf service class) for WiFi follows is the mapping
168 * that implemented at the 802.11 driver level when the mbuf service class is
169 * MBUF_SC_BE.
170 *
171 * This clashes with the recommended mapping documented by the IETF document
172 * draft-szigeti-tsvwg-ieee-802-11e-01.txt but we keep the mapping to maintain
173 * binary compatibility. Applications should use the network service type socket
174 * option instead to select L2 QoS marking instead of IP_TOS or IPV6_TCLASS.
175 */
176 static const struct dcsp_msc_map default_dscp_to_wifi_ac_map[] = {
177 { _DSCP_DF, MBUF_SC_BE }, /* RFC 2474 Standard */
178 { 1, MBUF_SC_BE }, /* */
179 { 2, MBUF_SC_BE }, /* */
180 { 3, MBUF_SC_BE }, /* */
181 { 4, MBUF_SC_BE }, /* */
182 { 5, MBUF_SC_BE }, /* */
183 { 6, MBUF_SC_BE }, /* */
184 { 7, MBUF_SC_BE }, /* */
185
186 { _DSCP_CS1, MBUF_SC_BK }, /* RFC 3662 Low-Priority Data */
187 { 9, MBUF_SC_BK }, /* */
188 { _DSCP_AF11, MBUF_SC_BK }, /* RFC 2597 High-Throughput Data */
189 { 11, MBUF_SC_BK }, /* */
190 { _DSCP_AF12, MBUF_SC_BK }, /* RFC 2597 High-Throughput Data */
191 { 13, MBUF_SC_BK }, /* */
192 { _DSCP_AF13, MBUF_SC_BK }, /* RFC 2597 High-Throughput Data */
193 { 15, MBUF_SC_BK }, /* */
194
195 { _DSCP_CS2, MBUF_SC_BK }, /* RFC 4594 OAM */
196 { 17, MBUF_SC_BK }, /* */
197 { _DSCP_AF21, MBUF_SC_BK }, /* RFC 2597 Low-Latency Data */
198 { 19, MBUF_SC_BK }, /* */
199 { _DSCP_AF22, MBUF_SC_BK }, /* RFC 2597 Low-Latency Data */
200 { 21, MBUF_SC_BK }, /* */
201 { _DSCP_AF23, MBUF_SC_BK }, /* RFC 2597 Low-Latency Data */
202 { 23, MBUF_SC_BK }, /* */
203
204 { _DSCP_CS3, MBUF_SC_BE }, /* RFC 2474 Broadcast Video */
205 { 25, MBUF_SC_BE }, /* */
206 { _DSCP_AF31, MBUF_SC_BE }, /* RFC 2597 Multimedia Streaming */
207 { 27, MBUF_SC_BE }, /* */
208 { _DSCP_AF32, MBUF_SC_BE }, /* RFC 2597 Multimedia Streaming */
209 { 29, MBUF_SC_BE }, /* */
210 { _DSCP_AF33, MBUF_SC_BE }, /* RFC 2597 Multimedia Streaming */
211 { 31, MBUF_SC_BE }, /* */
212
213 { _DSCP_CS4, MBUF_SC_VI }, /* RFC 2474 Real-Time Interactive */
214 { 33, MBUF_SC_VI }, /* */
215 { _DSCP_AF41, MBUF_SC_VI }, /* RFC 2597 Multimedia Conferencing */
216 { 35, MBUF_SC_VI }, /* */
217 { _DSCP_AF42, MBUF_SC_VI }, /* RFC 2597 Multimedia Conferencing */
218 { 37, MBUF_SC_VI }, /* */
219 { _DSCP_AF43, MBUF_SC_VI }, /* RFC 2597 Multimedia Conferencing */
220 { 39, MBUF_SC_VI }, /* */
221
222 { _DSCP_CS5, MBUF_SC_VI }, /* RFC 2474 Signaling */
223 { 41, MBUF_SC_VI }, /* */
224 { 42, MBUF_SC_VI }, /* */
225 { 43, MBUF_SC_VI }, /* */
226 { _DSCP_VA, MBUF_SC_VI }, /* RFC 5865 VOICE-ADMIT */
227 { 45, MBUF_SC_VI }, /* */
228 { _DSCP_EF, MBUF_SC_VI }, /* RFC 3246 Telephony */
229 { 47, MBUF_SC_VI }, /* */
230
231 { _DSCP_CS6, MBUF_SC_VO }, /* Wi-Fi WMM Certification: Chariot */
232 { 49, MBUF_SC_VO }, /* */
233 { 50, MBUF_SC_VO }, /* */
234 { 51, MBUF_SC_VO }, /* */
235 { 52, MBUF_SC_VO }, /* Wi-Fi WMM Certification: Sigma */
236 { 53, MBUF_SC_VO }, /* */
237 { 54, MBUF_SC_VO }, /* */
238 { 55, MBUF_SC_VO }, /* */
239
240 { _DSCP_CS7, MBUF_SC_VO }, /* Wi-Fi WMM Certification: Chariot */
241 { 57, MBUF_SC_VO }, /* */
242 { 58, MBUF_SC_VO }, /* */
243 { 59, MBUF_SC_VO }, /* */
244 { 60, MBUF_SC_VO }, /* */
245 { 61, MBUF_SC_VO }, /* */
246 { 62, MBUF_SC_VO }, /* */
247 { 63, MBUF_SC_VO }, /* */
248
249 { 255, MBUF_SC_UNSPEC } /* invalid DSCP to mark last entry */
250 };
251
252 mbuf_svc_class_t wifi_dscp_to_msc_array[DSCP_ARRAY_SIZE];
253
254 /*
255 * If there is no foreground activity on the interface for bg_switch_time
256 * seconds, the background connections can switch to foreground TCP
257 * congestion control.
258 */
259 #define TCP_BG_SWITCH_TIME 2 /* seconds */
260
261 #if (DEVELOPMENT || DEBUG)
262
263 static int tfp_count = 0;
264
265 static TAILQ_HEAD(, tclass_for_proc) tfp_head =
266 TAILQ_HEAD_INITIALIZER(tfp_head);
267
268 struct tclass_for_proc {
269 TAILQ_ENTRY(tclass_for_proc) tfp_link;
270 int tfp_class;
271 pid_t tfp_pid;
272 char tfp_pname[(2 * MAXCOMLEN) + 1];
273 u_int32_t tfp_qos_mode;
274 };
275
276 static int get_pid_tclass(struct so_tcdbg *);
277 static int get_pname_tclass(struct so_tcdbg *);
278 static int set_pid_tclass(struct so_tcdbg *);
279 static int set_pname_tclass(struct so_tcdbg *);
280 static int flush_pid_tclass(struct so_tcdbg *);
281 static int purge_tclass_for_proc(void);
282 static int flush_tclass_for_proc(void);
283 static void set_tclass_for_curr_proc(struct socket *);
284
285 /*
286 * Must be called with tclass_lock held
287 */
288 static struct tclass_for_proc *
289 find_tfp_by_pid(pid_t pid)
290 {
291 struct tclass_for_proc *tfp;
292
293 TAILQ_FOREACH(tfp, &tfp_head, tfp_link) {
294 if (tfp->tfp_pid == pid) {
295 break;
296 }
297 }
298 return tfp;
299 }
300
301 /*
302 * Must be called with tclass_lock held
303 */
304 static struct tclass_for_proc *
305 find_tfp_by_pname(const char *pname)
306 {
307 struct tclass_for_proc *tfp;
308
309 TAILQ_FOREACH(tfp, &tfp_head, tfp_link) {
310 if (strncmp(pname, tfp->tfp_pname,
311 sizeof(tfp->tfp_pname)) == 0) {
312 break;
313 }
314 }
315 return tfp;
316 }
317
318 __private_extern__ void
319 set_tclass_for_curr_proc(struct socket *so)
320 {
321 struct tclass_for_proc *tfp = NULL;
322 proc_t p = current_proc(); /* Not ref counted */
323 pid_t pid = proc_pid(p);
324 char *pname = proc_best_name(p);
325
326 lck_mtx_lock(tclass_lock);
327
328 TAILQ_FOREACH(tfp, &tfp_head, tfp_link) {
329 if ((tfp->tfp_pid == pid) || (tfp->tfp_pid == -1 &&
330 strncmp(pname, tfp->tfp_pname,
331 sizeof(tfp->tfp_pname)) == 0)) {
332 if (tfp->tfp_class != SO_TC_UNSPEC) {
333 so->so_traffic_class = tfp->tfp_class;
334 }
335
336 if (tfp->tfp_qos_mode == QOS_MODE_MARKING_POLICY_ENABLE) {
337 so->so_flags1 |= SOF1_QOSMARKING_ALLOWED;
338 } else if (tfp->tfp_qos_mode == QOS_MODE_MARKING_POLICY_DISABLE) {
339 so->so_flags1 &= ~SOF1_QOSMARKING_ALLOWED;
340 }
341 break;
342 }
343 }
344
345 lck_mtx_unlock(tclass_lock);
346 }
347
348 /*
349 * Purge entries with PIDs of exited processes
350 */
351 int
352 purge_tclass_for_proc(void)
353 {
354 int error = 0;
355 struct tclass_for_proc *tfp, *tvar;
356
357 lck_mtx_lock(tclass_lock);
358
359 TAILQ_FOREACH_SAFE(tfp, &tfp_head, tfp_link, tvar) {
360 proc_t p;
361
362 if (tfp->tfp_pid == -1) {
363 continue;
364 }
365 if ((p = proc_find(tfp->tfp_pid)) == NULL) {
366 tfp_count--;
367 TAILQ_REMOVE(&tfp_head, tfp, tfp_link);
368
369 _FREE(tfp, M_TEMP);
370 } else {
371 proc_rele(p);
372 }
373 }
374
375 lck_mtx_unlock(tclass_lock);
376
377 return error;
378 }
379
380 /*
381 * Remove one entry
382 * Must be called with tclass_lock held
383 */
384 static void
385 free_tclass_for_proc(struct tclass_for_proc *tfp)
386 {
387 if (tfp == NULL) {
388 return;
389 }
390 tfp_count--;
391 TAILQ_REMOVE(&tfp_head, tfp, tfp_link);
392 _FREE(tfp, M_TEMP);
393 }
394
395 /*
396 * Remove all entries
397 */
398 int
399 flush_tclass_for_proc(void)
400 {
401 int error = 0;
402 struct tclass_for_proc *tfp, *tvar;
403
404 lck_mtx_lock(tclass_lock);
405
406 TAILQ_FOREACH_SAFE(tfp, &tfp_head, tfp_link, tvar) {
407 free_tclass_for_proc(tfp);
408 }
409
410 lck_mtx_unlock(tclass_lock);
411
412 return error;
413 }
414
415 /*
416 * Must be called with tclass_lock held
417 */
418 static struct tclass_for_proc *
419 alloc_tclass_for_proc(pid_t pid, const char *pname)
420 {
421 struct tclass_for_proc *tfp;
422
423 if (pid == -1 && pname == NULL) {
424 return NULL;
425 }
426
427 tfp = _MALLOC(sizeof(struct tclass_for_proc), M_TEMP, M_NOWAIT | M_ZERO);
428 if (tfp == NULL) {
429 return NULL;
430 }
431
432 tfp->tfp_pid = pid;
433 /*
434 * Add per pid entries before per proc name so we can find
435 * a specific instance of a process before the general name base entry.
436 */
437 if (pid != -1) {
438 TAILQ_INSERT_HEAD(&tfp_head, tfp, tfp_link);
439 } else {
440 strlcpy(tfp->tfp_pname, pname, sizeof(tfp->tfp_pname));
441 TAILQ_INSERT_TAIL(&tfp_head, tfp, tfp_link);
442 }
443
444 tfp_count++;
445
446 return tfp;
447 }
448
449 /*
450 * SO_TC_UNSPEC for tclass means to remove the entry
451 */
452 int
453 set_pid_tclass(struct so_tcdbg *so_tcdbg)
454 {
455 int error = EINVAL;
456 proc_t p = NULL;
457 struct filedesc *fdp;
458 struct fileproc *fp;
459 struct tclass_for_proc *tfp;
460 int i;
461 pid_t pid = so_tcdbg->so_tcdbg_pid;
462 int tclass = so_tcdbg->so_tcdbg_tclass;
463 int netsvctype = so_tcdbg->so_tcdbg_netsvctype;
464
465 p = proc_find(pid);
466 if (p == NULL) {
467 printf("%s proc_find(%d) failed\n", __func__, pid);
468 goto done;
469 }
470
471 /* Need a tfp */
472 lck_mtx_lock(tclass_lock);
473
474 tfp = find_tfp_by_pid(pid);
475 if (tfp == NULL) {
476 tfp = alloc_tclass_for_proc(pid, NULL);
477 if (tfp == NULL) {
478 lck_mtx_unlock(tclass_lock);
479 error = ENOBUFS;
480 goto done;
481 }
482 }
483 tfp->tfp_class = tclass;
484 tfp->tfp_qos_mode = so_tcdbg->so_tcbbg_qos_mode;
485
486 lck_mtx_unlock(tclass_lock);
487
488 if (tfp != NULL) {
489 proc_fdlock(p);
490
491 fdp = p->p_fd;
492 for (i = 0; i < fdp->fd_nfiles; i++) {
493 struct socket *so;
494
495 fp = fdp->fd_ofiles[i];
496 if (fp == NULL ||
497 (fdp->fd_ofileflags[i] & UF_RESERVED) != 0 ||
498 FILEGLOB_DTYPE(fp->f_fglob) != DTYPE_SOCKET) {
499 continue;
500 }
501
502 so = (struct socket *)fp->f_fglob->fg_data;
503 if (SOCK_DOM(so) != PF_INET && SOCK_DOM(so) != PF_INET6) {
504 continue;
505 }
506
507 socket_lock(so, 1);
508 if (tfp->tfp_qos_mode == QOS_MODE_MARKING_POLICY_ENABLE) {
509 so->so_flags1 |= SOF1_QOSMARKING_ALLOWED;
510 } else if (tfp->tfp_qos_mode == QOS_MODE_MARKING_POLICY_DISABLE) {
511 so->so_flags1 &= ~SOF1_QOSMARKING_ALLOWED;
512 }
513 socket_unlock(so, 1);
514
515 if (netsvctype != _NET_SERVICE_TYPE_UNSPEC) {
516 error = sock_setsockopt(so, SOL_SOCKET,
517 SO_NET_SERVICE_TYPE, &netsvctype, sizeof(int));
518 }
519 if (tclass != SO_TC_UNSPEC) {
520 error = sock_setsockopt(so, SOL_SOCKET,
521 SO_TRAFFIC_CLASS, &tclass, sizeof(int));
522 }
523 }
524
525 proc_fdunlock(p);
526 }
527
528 error = 0;
529 done:
530 if (p != NULL) {
531 proc_rele(p);
532 }
533
534 return error;
535 }
536
537 int
538 set_pname_tclass(struct so_tcdbg *so_tcdbg)
539 {
540 int error = EINVAL;
541 struct tclass_for_proc *tfp;
542
543 lck_mtx_lock(tclass_lock);
544
545 tfp = find_tfp_by_pname(so_tcdbg->so_tcdbg_pname);
546 if (tfp == NULL) {
547 tfp = alloc_tclass_for_proc(-1, so_tcdbg->so_tcdbg_pname);
548 if (tfp == NULL) {
549 lck_mtx_unlock(tclass_lock);
550 error = ENOBUFS;
551 goto done;
552 }
553 }
554 tfp->tfp_class = so_tcdbg->so_tcdbg_tclass;
555 tfp->tfp_qos_mode = so_tcdbg->so_tcbbg_qos_mode;
556
557 lck_mtx_unlock(tclass_lock);
558
559 error = 0;
560 done:
561
562 return error;
563 }
564
565 static int
566 flush_pid_tclass(struct so_tcdbg *so_tcdbg)
567 {
568 pid_t pid = so_tcdbg->so_tcdbg_pid;
569 int tclass = so_tcdbg->so_tcdbg_tclass;
570 struct filedesc *fdp;
571 int error = EINVAL;
572 proc_t p;
573 int i;
574
575 p = proc_find(pid);
576 if (p == PROC_NULL) {
577 printf("%s proc_find(%d) failed\n", __func__, pid);
578 goto done;
579 }
580
581 proc_fdlock(p);
582 fdp = p->p_fd;
583 for (i = 0; i < fdp->fd_nfiles; i++) {
584 struct socket *so;
585 struct fileproc *fp;
586
587 fp = fdp->fd_ofiles[i];
588 if (fp == NULL ||
589 (fdp->fd_ofileflags[i] & UF_RESERVED) != 0 ||
590 FILEGLOB_DTYPE(fp->f_fglob) != DTYPE_SOCKET) {
591 continue;
592 }
593
594 so = (struct socket *)fp->f_fglob->fg_data;
595 error = sock_setsockopt(so, SOL_SOCKET, SO_FLUSH, &tclass,
596 sizeof(tclass));
597 if (error != 0) {
598 printf("%s: setsockopt(SO_FLUSH) (so=0x%llx, fd=%d, "
599 "tclass=%d) failed %d\n", __func__,
600 (uint64_t)VM_KERNEL_ADDRPERM(so), i, tclass,
601 error);
602 error = 0;
603 }
604 }
605 proc_fdunlock(p);
606
607 error = 0;
608 done:
609 if (p != PROC_NULL) {
610 proc_rele(p);
611 }
612
613 return error;
614 }
615
616 int
617 get_pid_tclass(struct so_tcdbg *so_tcdbg)
618 {
619 int error = EINVAL;
620 proc_t p = NULL;
621 struct tclass_for_proc *tfp;
622 pid_t pid = so_tcdbg->so_tcdbg_pid;
623
624 so_tcdbg->so_tcdbg_tclass = SO_TC_UNSPEC; /* Means not set */
625
626 p = proc_find(pid);
627 if (p == NULL) {
628 printf("%s proc_find(%d) failed\n", __func__, pid);
629 goto done;
630 }
631
632 /* Need a tfp */
633 lck_mtx_lock(tclass_lock);
634
635 tfp = find_tfp_by_pid(pid);
636 if (tfp != NULL) {
637 so_tcdbg->so_tcdbg_tclass = tfp->tfp_class;
638 so_tcdbg->so_tcbbg_qos_mode = tfp->tfp_qos_mode;
639 error = 0;
640 }
641 lck_mtx_unlock(tclass_lock);
642 done:
643 if (p != NULL) {
644 proc_rele(p);
645 }
646
647 return error;
648 }
649
650 int
651 get_pname_tclass(struct so_tcdbg *so_tcdbg)
652 {
653 int error = EINVAL;
654 struct tclass_for_proc *tfp;
655
656 so_tcdbg->so_tcdbg_tclass = SO_TC_UNSPEC; /* Means not set */
657
658 /* Need a tfp */
659 lck_mtx_lock(tclass_lock);
660
661 tfp = find_tfp_by_pname(so_tcdbg->so_tcdbg_pname);
662 if (tfp != NULL) {
663 so_tcdbg->so_tcdbg_tclass = tfp->tfp_class;
664 so_tcdbg->so_tcbbg_qos_mode = tfp->tfp_qos_mode;
665 error = 0;
666 }
667 lck_mtx_unlock(tclass_lock);
668
669 return error;
670 }
671
672 static int
673 delete_tclass_for_pid_pname(struct so_tcdbg *so_tcdbg)
674 {
675 int error = EINVAL;
676 pid_t pid = so_tcdbg->so_tcdbg_pid;
677 struct tclass_for_proc *tfp = NULL;
678
679 lck_mtx_lock(tclass_lock);
680
681 if (pid != -1) {
682 tfp = find_tfp_by_pid(pid);
683 } else {
684 tfp = find_tfp_by_pname(so_tcdbg->so_tcdbg_pname);
685 }
686
687 if (tfp != NULL) {
688 free_tclass_for_proc(tfp);
689 error = 0;
690 }
691
692 lck_mtx_unlock(tclass_lock);
693
694 return error;
695 }
696
697 /*
698 * Setting options requires privileges
699 */
700 __private_extern__ int
701 so_set_tcdbg(struct socket *so, struct so_tcdbg *so_tcdbg)
702 {
703 int error = 0;
704
705 if ((so->so_state & SS_PRIV) == 0) {
706 return EPERM;
707 }
708
709 socket_unlock(so, 0);
710
711 switch (so_tcdbg->so_tcdbg_cmd) {
712 case SO_TCDBG_PID:
713 error = set_pid_tclass(so_tcdbg);
714 break;
715
716 case SO_TCDBG_PNAME:
717 error = set_pname_tclass(so_tcdbg);
718 break;
719
720 case SO_TCDBG_PURGE:
721 error = purge_tclass_for_proc();
722 break;
723
724 case SO_TCDBG_FLUSH:
725 error = flush_tclass_for_proc();
726 break;
727
728 case SO_TCDBG_DELETE:
729 error = delete_tclass_for_pid_pname(so_tcdbg);
730 break;
731
732 case SO_TCDBG_TCFLUSH_PID:
733 error = flush_pid_tclass(so_tcdbg);
734 break;
735
736 default:
737 error = EINVAL;
738 break;
739 }
740
741 socket_lock(so, 0);
742
743 return error;
744 }
745
746 /*
747 * Not required to be privileged to get
748 */
749 __private_extern__ int
750 sogetopt_tcdbg(struct socket *so, struct sockopt *sopt)
751 {
752 int error = 0;
753 struct so_tcdbg so_tcdbg;
754 void *buf = NULL;
755 size_t len = sopt->sopt_valsize;
756
757 error = sooptcopyin(sopt, &so_tcdbg, sizeof(struct so_tcdbg),
758 sizeof(struct so_tcdbg));
759 if (error != 0) {
760 return error;
761 }
762
763 sopt->sopt_valsize = len;
764
765 socket_unlock(so, 0);
766
767 switch (so_tcdbg.so_tcdbg_cmd) {
768 case SO_TCDBG_PID:
769 error = get_pid_tclass(&so_tcdbg);
770 break;
771
772 case SO_TCDBG_PNAME:
773 error = get_pname_tclass(&so_tcdbg);
774 break;
775
776 case SO_TCDBG_COUNT:
777 lck_mtx_lock(tclass_lock);
778 so_tcdbg.so_tcdbg_count = tfp_count;
779 lck_mtx_unlock(tclass_lock);
780 break;
781
782 case SO_TCDBG_LIST: {
783 struct tclass_for_proc *tfp;
784 int n, alloc_count;
785 struct so_tcdbg *ptr;
786
787 lck_mtx_lock(tclass_lock);
788 if ((alloc_count = tfp_count) == 0) {
789 lck_mtx_unlock(tclass_lock);
790 error = EINVAL;
791 break;
792 }
793 len = alloc_count * sizeof(struct so_tcdbg);
794 lck_mtx_unlock(tclass_lock);
795
796 buf = _MALLOC(len, M_TEMP, M_WAITOK | M_ZERO);
797 if (buf == NULL) {
798 error = ENOBUFS;
799 break;
800 }
801
802 lck_mtx_lock(tclass_lock);
803 n = 0;
804 ptr = (struct so_tcdbg *)buf;
805 TAILQ_FOREACH(tfp, &tfp_head, tfp_link) {
806 if (++n > alloc_count) {
807 break;
808 }
809 if (tfp->tfp_pid != -1) {
810 ptr->so_tcdbg_cmd = SO_TCDBG_PID;
811 ptr->so_tcdbg_pid = tfp->tfp_pid;
812 } else {
813 ptr->so_tcdbg_cmd = SO_TCDBG_PNAME;
814 ptr->so_tcdbg_pid = -1;
815 strlcpy(ptr->so_tcdbg_pname,
816 tfp->tfp_pname,
817 sizeof(ptr->so_tcdbg_pname));
818 }
819 ptr->so_tcdbg_tclass = tfp->tfp_class;
820 ptr->so_tcbbg_qos_mode = tfp->tfp_qos_mode;
821 ptr++;
822 }
823
824 lck_mtx_unlock(tclass_lock);
825 }
826 break;
827
828 default:
829 error = EINVAL;
830 break;
831 }
832
833 socket_lock(so, 0);
834
835 if (error == 0) {
836 if (buf == NULL) {
837 error = sooptcopyout(sopt, &so_tcdbg,
838 sizeof(struct so_tcdbg));
839 } else {
840 error = sooptcopyout(sopt, buf, len);
841 _FREE(buf, M_TEMP);
842 }
843 }
844 return error;
845 }
846
847 #endif /* (DEVELOPMENT || DEBUG) */
848
849 int
850 so_get_netsvc_marking_level(struct socket *so)
851 {
852 int marking_level = NETSVC_MRKNG_UNKNOWN;
853 struct ifnet *ifp = NULL;
854
855 switch (SOCK_DOM(so)) {
856 case PF_INET: {
857 struct inpcb *inp = sotoinpcb(so);
858
859 if (inp != NULL) {
860 ifp = inp->inp_last_outifp;
861 }
862 break;
863 }
864 case PF_INET6: {
865 struct in6pcb *in6p = sotoin6pcb(so);
866
867 if (in6p != NULL) {
868 ifp = in6p->in6p_last_outifp;
869 }
870 break;
871 }
872 default:
873 break;
874 }
875 if (ifp != NULL) {
876 if ((ifp->if_eflags &
877 (IFEF_QOSMARKING_ENABLED | IFEF_QOSMARKING_CAPABLE)) ==
878 (IFEF_QOSMARKING_ENABLED | IFEF_QOSMARKING_CAPABLE)) {
879 if ((so->so_flags1 & SOF1_QOSMARKING_ALLOWED)) {
880 marking_level = NETSVC_MRKNG_LVL_L3L2_ALL;
881 } else {
882 marking_level = NETSVC_MRKNG_LVL_L3L2_BK;
883 }
884 } else {
885 marking_level = NETSVC_MRKNG_LVL_L2;
886 }
887 }
888 return marking_level;
889 }
890
891 __private_extern__ int
892 so_set_traffic_class(struct socket *so, int optval)
893 {
894 int error = 0;
895
896 if (optval < SO_TC_BE || optval > SO_TC_CTL) {
897 error = EINVAL;
898 } else {
899 switch (optval) {
900 case _SO_TC_BK:
901 optval = SO_TC_BK;
902 break;
903 case _SO_TC_VI:
904 optval = SO_TC_VI;
905 break;
906 case _SO_TC_VO:
907 optval = SO_TC_VO;
908 break;
909 default:
910 if (!SO_VALID_TC(optval)) {
911 error = EINVAL;
912 }
913 break;
914 }
915
916 if (error == 0) {
917 int oldval = so->so_traffic_class;
918
919 VERIFY(SO_VALID_TC(optval));
920 so->so_traffic_class = optval;
921
922 if ((SOCK_DOM(so) == PF_INET ||
923 SOCK_DOM(so) == PF_INET6) &&
924 SOCK_TYPE(so) == SOCK_STREAM) {
925 set_tcp_stream_priority(so);
926 }
927
928 if ((SOCK_DOM(so) == PF_INET ||
929 SOCK_DOM(so) == PF_INET6) &&
930 optval != oldval && (optval == SO_TC_BK_SYS ||
931 oldval == SO_TC_BK_SYS)) {
932 /*
933 * If the app switches from BK_SYS to something
934 * else, resume the socket if it was suspended.
935 */
936 if (oldval == SO_TC_BK_SYS) {
937 inp_reset_fc_state(so->so_pcb);
938 }
939
940 SOTHROTTLELOG("throttle[%d]: so 0x%llx "
941 "[%d,%d] opportunistic %s\n", so->last_pid,
942 (uint64_t)VM_KERNEL_ADDRPERM(so),
943 SOCK_DOM(so), SOCK_TYPE(so),
944 (optval == SO_TC_BK_SYS) ? "ON" : "OFF");
945 }
946 }
947 }
948 return error;
949 }
950
951 __private_extern__ int
952 so_set_net_service_type(struct socket *so, int netsvctype)
953 {
954 int sotc;
955 int error;
956
957 if (!IS_VALID_NET_SERVICE_TYPE(netsvctype)) {
958 return EINVAL;
959 }
960
961 sotc = sotc_by_netservicetype[netsvctype];
962 error = so_set_traffic_class(so, sotc);
963 if (error != 0) {
964 return error;
965 }
966 so->so_netsvctype = netsvctype;
967 so->so_flags1 |= SOF1_TC_NET_SERV_TYPE;
968
969 return 0;
970 }
971
972 __private_extern__ void
973 so_set_default_traffic_class(struct socket *so)
974 {
975 so->so_traffic_class = SO_TC_BE;
976
977 if ((SOCK_DOM(so) == PF_INET || SOCK_DOM(so) == PF_INET6)) {
978 if (net_qos_policy_restricted == 0) {
979 so->so_flags1 |= SOF1_QOSMARKING_ALLOWED;
980 }
981 #if (DEVELOPMENT || DEBUG)
982 if (tfp_count > 0) {
983 set_tclass_for_curr_proc(so);
984 }
985 #endif /* (DEVELOPMENT || DEBUG) */
986 }
987 }
988
989 __private_extern__ int
990 so_set_opportunistic(struct socket *so, int optval)
991 {
992 return so_set_traffic_class(so, (optval == 0) ?
993 SO_TC_BE : SO_TC_BK_SYS);
994 }
995
996 __private_extern__ int
997 so_get_opportunistic(struct socket *so)
998 {
999 return so->so_traffic_class == SO_TC_BK_SYS;
1000 }
1001
1002 __private_extern__ int
1003 so_tc_from_control(struct mbuf *control, int *out_netsvctype)
1004 {
1005 struct cmsghdr *cm;
1006 int sotc = SO_TC_UNSPEC;
1007
1008 *out_netsvctype = _NET_SERVICE_TYPE_UNSPEC;
1009
1010 for (cm = M_FIRST_CMSGHDR(control);
1011 is_cmsg_valid(control, cm);
1012 cm = M_NXT_CMSGHDR(control, cm)) {
1013 int val;
1014
1015 if (cm->cmsg_level != SOL_SOCKET ||
1016 cm->cmsg_len != CMSG_LEN(sizeof(int))) {
1017 continue;
1018 }
1019 val = *(int *)(void *)CMSG_DATA(cm);
1020 /*
1021 * The first valid option wins
1022 */
1023 switch (cm->cmsg_type) {
1024 case SO_TRAFFIC_CLASS:
1025 if (SO_VALID_TC(val)) {
1026 sotc = val;
1027 return sotc;
1028 /* NOT REACHED */
1029 } else if (val < SO_TC_NET_SERVICE_OFFSET) {
1030 break;
1031 }
1032 /*
1033 * Handle the case SO_NET_SERVICE_TYPE values are
1034 * passed using SO_TRAFFIC_CLASS
1035 */
1036 val = val - SO_TC_NET_SERVICE_OFFSET;
1037 /* FALLTHROUGH */
1038 case SO_NET_SERVICE_TYPE:
1039 if (!IS_VALID_NET_SERVICE_TYPE(val)) {
1040 break;
1041 }
1042 *out_netsvctype = val;
1043 sotc = sotc_by_netservicetype[val];
1044 return sotc;
1045 /* NOT REACHED */
1046 default:
1047 break;
1048 }
1049 }
1050
1051 return sotc;
1052 }
1053
1054 __private_extern__ void
1055 so_recv_data_stat(struct socket *so, struct mbuf *m, size_t off)
1056 {
1057 uint32_t mtc = m_get_traffic_class(m);
1058
1059 if (mtc >= SO_TC_STATS_MAX) {
1060 mtc = MBUF_TC_BE;
1061 }
1062
1063 so->so_tc_stats[mtc].rxpackets += 1;
1064 so->so_tc_stats[mtc].rxbytes +=
1065 ((m->m_flags & M_PKTHDR) ? m->m_pkthdr.len : 0) + off;
1066 }
1067
1068 __private_extern__ void
1069 so_inc_recv_data_stat(struct socket *so, size_t pkts, size_t bytes,
1070 uint32_t mtc)
1071 {
1072 if (mtc >= SO_TC_STATS_MAX) {
1073 mtc = MBUF_TC_BE;
1074 }
1075
1076 so->so_tc_stats[mtc].rxpackets += pkts;
1077 so->so_tc_stats[mtc].rxbytes += bytes;
1078 }
1079
1080 static inline int
1081 so_throttle_best_effort(struct socket *so, struct ifnet *ifp)
1082 {
1083 u_int32_t uptime = net_uptime();
1084 return soissrcbesteffort(so) &&
1085 net_io_policy_throttle_best_effort == 1 &&
1086 ifp->if_rt_sendts > 0 &&
1087 (int)(uptime - ifp->if_rt_sendts) <= TCP_BG_SWITCH_TIME;
1088 }
1089
1090 __private_extern__ void
1091 set_tcp_stream_priority(struct socket *so)
1092 {
1093 struct inpcb *inp = sotoinpcb(so);
1094 struct tcpcb *tp = intotcpcb(inp);
1095 struct ifnet *outifp;
1096 u_char old_cc = tp->tcp_cc_index;
1097 int recvbg = IS_TCP_RECV_BG(so);
1098 bool is_local = false, fg_active = false;
1099 u_int32_t uptime;
1100
1101 VERIFY((SOCK_CHECK_DOM(so, PF_INET) ||
1102 SOCK_CHECK_DOM(so, PF_INET6)) &&
1103 SOCK_CHECK_TYPE(so, SOCK_STREAM) &&
1104 SOCK_CHECK_PROTO(so, IPPROTO_TCP));
1105
1106 /* Return if the socket is in a terminal state */
1107 if (inp->inp_state == INPCB_STATE_DEAD) {
1108 return;
1109 }
1110
1111 outifp = inp->inp_last_outifp;
1112 uptime = net_uptime();
1113
1114 /*
1115 * If the socket was marked as a background socket or if the
1116 * traffic class is set to background with traffic class socket
1117 * option then make both send and recv side of the stream to be
1118 * background. The variable sotcdb which can be set with sysctl
1119 * is used to disable these settings for testing.
1120 */
1121 if (outifp == NULL || (outifp->if_flags & IFF_LOOPBACK)) {
1122 is_local = true;
1123 }
1124
1125 /* Check if there has been recent foreground activity */
1126 if (outifp != NULL) {
1127 /*
1128 * If the traffic source is background, check if
1129 * if it can be switched to foreground. This can
1130 * happen when there is no indication of foreground
1131 * activity.
1132 */
1133 if (soissrcbackground(so) && outifp->if_fg_sendts > 0 &&
1134 (int)(uptime - outifp->if_fg_sendts) <= TCP_BG_SWITCH_TIME) {
1135 fg_active = true;
1136 }
1137
1138 /*
1139 * The traffic source is best-effort -- check if
1140 * the policy to throttle best effort is enabled
1141 * and there was realtime activity on this
1142 * interface recently. If this is true, enable
1143 * algorithms that respond to increased latency
1144 * on best-effort traffic.
1145 */
1146 if (so_throttle_best_effort(so, outifp)) {
1147 fg_active = true;
1148 }
1149 }
1150
1151 /*
1152 * System initiated background traffic like cloud uploads should
1153 * always use background delay sensitive algorithms. This will
1154 * make the stream more responsive to other streams on the user's
1155 * network and it will minimize latency induced.
1156 */
1157 if (fg_active || IS_SO_TC_BACKGROUNDSYSTEM(so->so_traffic_class)) {
1158 /*
1159 * If the interface that the connection is using is
1160 * loopback, do not use background congestion
1161 * control algorithm.
1162 *
1163 * If there has been recent foreground activity or if
1164 * there was an indication that a foreground application
1165 * is going to use networking (net_io_policy_throttled),
1166 * switch the backgroung streams to use background
1167 * congestion control algorithm. Otherwise, even background
1168 * flows can move into foreground.
1169 */
1170 if ((sotcdb & SOTCDB_NO_SENDTCPBG) != 0 || is_local ||
1171 !IS_SO_TC_BACKGROUNDSYSTEM(so->so_traffic_class)) {
1172 if (old_cc == TCP_CC_ALGO_BACKGROUND_INDEX) {
1173 tcp_set_foreground_cc(so);
1174 }
1175 } else {
1176 if (old_cc != TCP_CC_ALGO_BACKGROUND_INDEX) {
1177 tcp_set_background_cc(so);
1178 }
1179 }
1180
1181 /* Set receive side background flags */
1182 if ((sotcdb & SOTCDB_NO_RECVTCPBG) != 0 || is_local ||
1183 !IS_SO_TC_BACKGROUNDSYSTEM(so->so_traffic_class)) {
1184 tcp_clear_recv_bg(so);
1185 } else {
1186 tcp_set_recv_bg(so);
1187 }
1188 } else {
1189 tcp_clear_recv_bg(so);
1190 if (old_cc == TCP_CC_ALGO_BACKGROUND_INDEX) {
1191 tcp_set_foreground_cc(so);
1192 }
1193 }
1194
1195 if (old_cc != tp->tcp_cc_index || recvbg != IS_TCP_RECV_BG(so)) {
1196 SOTHROTTLELOG("throttle[%d]: so 0x%llx [%d,%d] TCP %s send; "
1197 "%s recv\n", so->last_pid,
1198 (uint64_t)VM_KERNEL_ADDRPERM(so),
1199 SOCK_DOM(so), SOCK_TYPE(so),
1200 (tp->tcp_cc_index == TCP_CC_ALGO_BACKGROUND_INDEX) ?
1201 "background" : "foreground",
1202 IS_TCP_RECV_BG(so) ? "background" : "foreground");
1203 }
1204 }
1205
1206 /*
1207 * Set traffic class to an IPv4 or IPv6 packet
1208 * - mark the mbuf
1209 * - set the DSCP code following the WMM mapping
1210 */
1211 __private_extern__ void
1212 set_packet_service_class(struct mbuf *m, struct socket *so,
1213 int sotc, u_int32_t flags)
1214 {
1215 mbuf_svc_class_t msc = MBUF_SC_BE; /* Best effort by default */
1216 struct inpcb *inp = sotoinpcb(so); /* in6pcb and inpcb are the same */
1217
1218 if (!(m->m_flags & M_PKTHDR)) {
1219 return;
1220 }
1221
1222 /*
1223 * Here is the precedence:
1224 * 1) TRAFFIC_MGT_SO_BACKGROUND trumps all
1225 * 2) Traffic class passed via ancillary data to sendmsdg(2)
1226 * 3) Traffic class socket option last
1227 */
1228 if (sotc != SO_TC_UNSPEC) {
1229 VERIFY(SO_VALID_TC(sotc));
1230 msc = so_tc2msc(sotc);
1231 /* Assert because tc must have been valid */
1232 VERIFY(MBUF_VALID_SC(msc));
1233 }
1234
1235 /*
1236 * If TRAFFIC_MGT_SO_BACKGROUND is set or policy to throttle
1237 * best effort is set, depress the priority.
1238 */
1239 if (!IS_MBUF_SC_BACKGROUND(msc) && soisthrottled(so)) {
1240 msc = MBUF_SC_BK;
1241 }
1242
1243 if (IS_MBUF_SC_BESTEFFORT(msc) && inp->inp_last_outifp != NULL &&
1244 so_throttle_best_effort(so, inp->inp_last_outifp)) {
1245 msc = MBUF_SC_BK;
1246 }
1247
1248 if (soissrcbackground(so)) {
1249 m->m_pkthdr.pkt_flags |= PKTF_SO_BACKGROUND;
1250 }
1251
1252 if (soissrcrealtime(so) || IS_MBUF_SC_REALTIME(msc)) {
1253 m->m_pkthdr.pkt_flags |= PKTF_SO_REALTIME;
1254 }
1255 /*
1256 * Set the traffic class in the mbuf packet header svc field
1257 */
1258 if (sotcdb & SOTCDB_NO_MTC) {
1259 goto no_mbtc;
1260 }
1261
1262 /*
1263 * Elevate service class if the packet is a pure TCP ACK.
1264 * We can do this only when the flow is not a background
1265 * flow and the outgoing interface supports
1266 * transmit-start model.
1267 */
1268 if (!IS_MBUF_SC_BACKGROUND(msc) &&
1269 (flags & (PKT_SCF_TCP_ACK | PKT_SCF_TCP_SYN)) != 0) {
1270 msc = MBUF_SC_CTL;
1271 }
1272
1273 (void) m_set_service_class(m, msc);
1274
1275 /*
1276 * Set the privileged traffic auxiliary flag if applicable,
1277 * or clear it.
1278 */
1279 if (!(sotcdb & SOTCDB_NO_PRIVILEGED) && soisprivilegedtraffic(so) &&
1280 msc != MBUF_SC_UNSPEC) {
1281 m->m_pkthdr.pkt_flags |= PKTF_PRIO_PRIVILEGED;
1282 } else {
1283 m->m_pkthdr.pkt_flags &= ~PKTF_PRIO_PRIVILEGED;
1284 }
1285
1286 no_mbtc:
1287 /*
1288 * For TCP with background traffic class switch CC algo based on sysctl
1289 */
1290 if (so->so_type == SOCK_STREAM) {
1291 set_tcp_stream_priority(so);
1292 }
1293
1294 so_tc_update_stats(m, so, msc);
1295 }
1296
1297 __private_extern__ void
1298 so_tc_update_stats(struct mbuf *m, struct socket *so, mbuf_svc_class_t msc)
1299 {
1300 mbuf_traffic_class_t mtc;
1301
1302 /*
1303 * Assume socket and mbuf traffic class values are the same
1304 * Also assume the socket lock is held. Note that the stats
1305 * at the socket layer are reduced down to the legacy traffic
1306 * classes; we could/should potentially expand so_tc_stats[].
1307 */
1308 mtc = MBUF_SC2TC(msc);
1309 VERIFY(mtc < SO_TC_STATS_MAX);
1310 so->so_tc_stats[mtc].txpackets += 1;
1311 so->so_tc_stats[mtc].txbytes += m->m_pkthdr.len;
1312 }
1313
1314 __private_extern__ void
1315 socket_tclass_init(void)
1316 {
1317 _CASSERT(_SO_TC_MAX == SO_TC_STATS_MAX);
1318
1319 tclass_lck_grp_attr = lck_grp_attr_alloc_init();
1320 tclass_lck_grp = lck_grp_alloc_init("tclass", tclass_lck_grp_attr);
1321 tclass_lck_attr = lck_attr_alloc_init();
1322 lck_mtx_init(tclass_lock, tclass_lck_grp, tclass_lck_attr);
1323 }
1324
1325 __private_extern__ mbuf_svc_class_t
1326 so_tc2msc(int tc)
1327 {
1328 mbuf_svc_class_t msc;
1329
1330 switch (tc) {
1331 case SO_TC_BK_SYS:
1332 msc = MBUF_SC_BK_SYS;
1333 break;
1334 case SO_TC_BK:
1335 case _SO_TC_BK:
1336 msc = MBUF_SC_BK;
1337 break;
1338 case SO_TC_BE:
1339 msc = MBUF_SC_BE;
1340 break;
1341 case SO_TC_RD:
1342 msc = MBUF_SC_RD;
1343 break;
1344 case SO_TC_OAM:
1345 msc = MBUF_SC_OAM;
1346 break;
1347 case SO_TC_AV:
1348 msc = MBUF_SC_AV;
1349 break;
1350 case SO_TC_RV:
1351 msc = MBUF_SC_RV;
1352 break;
1353 case SO_TC_VI:
1354 case _SO_TC_VI:
1355 msc = MBUF_SC_VI;
1356 break;
1357 case SO_TC_NETSVC_SIG:
1358 msc = MBUF_SC_SIG;
1359 break;
1360 case SO_TC_VO:
1361 case _SO_TC_VO:
1362 msc = MBUF_SC_VO;
1363 break;
1364 case SO_TC_CTL:
1365 msc = MBUF_SC_CTL;
1366 break;
1367 case SO_TC_ALL:
1368 default:
1369 msc = MBUF_SC_UNSPEC;
1370 break;
1371 }
1372
1373 return msc;
1374 }
1375
1376 __private_extern__ int
1377 so_svc2tc(mbuf_svc_class_t svc)
1378 {
1379 switch (svc) {
1380 case MBUF_SC_BK_SYS:
1381 return SO_TC_BK_SYS;
1382 case MBUF_SC_BK:
1383 return SO_TC_BK;
1384 case MBUF_SC_BE:
1385 return SO_TC_BE;
1386 case MBUF_SC_RD:
1387 return SO_TC_RD;
1388 case MBUF_SC_OAM:
1389 return SO_TC_OAM;
1390 case MBUF_SC_AV:
1391 return SO_TC_AV;
1392 case MBUF_SC_RV:
1393 return SO_TC_RV;
1394 case MBUF_SC_VI:
1395 return SO_TC_VI;
1396 case MBUF_SC_SIG:
1397 return SO_TC_NETSVC_SIG;
1398 case MBUF_SC_VO:
1399 return SO_TC_VO;
1400 case MBUF_SC_CTL:
1401 return SO_TC_CTL;
1402 case MBUF_SC_UNSPEC:
1403 default:
1404 return SO_TC_BE;
1405 }
1406 }
1407
1408 /*
1409 * LRO is turned on for AV streaming class.
1410 */
1411 void
1412 so_set_lro(struct socket *so, int optval)
1413 {
1414 if (optval == SO_TC_AV) {
1415 so->so_flags |= SOF_USELRO;
1416 } else {
1417 if (so->so_flags & SOF_USELRO) {
1418 /* transition to non LRO class */
1419 so->so_flags &= ~SOF_USELRO;
1420 struct inpcb *inp = sotoinpcb(so);
1421 struct tcpcb *tp = NULL;
1422 if (inp) {
1423 tp = intotcpcb(inp);
1424 if (tp && (tp->t_flagsext & TF_LRO_OFFLOADED)) {
1425 tcp_lro_remove_state(inp->inp_laddr,
1426 inp->inp_faddr,
1427 inp->inp_lport,
1428 inp->inp_fport);
1429 tp->t_flagsext &= ~TF_LRO_OFFLOADED;
1430 }
1431 }
1432 }
1433 }
1434 }
1435
1436 static size_t
1437 sotc_index(int sotc)
1438 {
1439 switch (sotc) {
1440 case SO_TC_BK_SYS:
1441 return SOTCIX_BK_SYS;
1442 case _SO_TC_BK:
1443 case SO_TC_BK:
1444 return SOTCIX_BK;
1445
1446 case SO_TC_BE:
1447 return SOTCIX_BE;
1448 case SO_TC_RD:
1449 return SOTCIX_RD;
1450 case SO_TC_OAM:
1451 return SOTCIX_OAM;
1452
1453 case SO_TC_AV:
1454 return SOTCIX_AV;
1455 case SO_TC_RV:
1456 return SOTCIX_RV;
1457 case _SO_TC_VI:
1458 case SO_TC_VI:
1459 return SOTCIX_VI;
1460
1461 case _SO_TC_VO:
1462 case SO_TC_VO:
1463 return SOTCIX_VO;
1464 case SO_TC_CTL:
1465 return SOTCIX_CTL;
1466
1467 default:
1468 break;
1469 }
1470 /*
1471 * Unknown traffic class value
1472 */
1473 return SIZE_T_MAX;
1474 }
1475
1476 /*
1477 * Pass NULL ifp for default map
1478 */
1479 static errno_t
1480 set_netsvctype_dscp_map(size_t in_count,
1481 const struct netsvctype_dscp_map *netsvctype_dscp_map)
1482 {
1483 size_t i;
1484 struct net_qos_dscp_map *net_qos_dscp_map = NULL;
1485 int netsvctype;
1486
1487 /*
1488 * Do not accept more that max number of distinct DSCPs
1489 */
1490 if (in_count > _MAX_DSCP || netsvctype_dscp_map == NULL) {
1491 return EINVAL;
1492 }
1493
1494 /*
1495 * Validate input parameters
1496 */
1497 for (i = 0; i < in_count; i++) {
1498 if (!IS_VALID_NET_SERVICE_TYPE(netsvctype_dscp_map[i].netsvctype)) {
1499 return EINVAL;
1500 }
1501 if (netsvctype_dscp_map[i].dscp > _MAX_DSCP) {
1502 return EINVAL;
1503 }
1504 }
1505
1506 net_qos_dscp_map = &default_net_qos_dscp_map;
1507
1508 for (i = 0; i < in_count; i++) {
1509 netsvctype = netsvctype_dscp_map[i].netsvctype;
1510
1511 net_qos_dscp_map->netsvctype_to_dscp[netsvctype] =
1512 netsvctype_dscp_map[i].dscp;
1513 }
1514 for (netsvctype = 0; netsvctype < _NET_SERVICE_TYPE_COUNT; netsvctype++) {
1515 switch (netsvctype) {
1516 case NET_SERVICE_TYPE_BE:
1517 case NET_SERVICE_TYPE_BK:
1518 case NET_SERVICE_TYPE_VI:
1519 case NET_SERVICE_TYPE_VO:
1520 case NET_SERVICE_TYPE_RV:
1521 case NET_SERVICE_TYPE_AV:
1522 case NET_SERVICE_TYPE_OAM:
1523 case NET_SERVICE_TYPE_RD: {
1524 size_t sotcix;
1525
1526 sotcix = sotc_index(sotc_by_netservicetype[netsvctype]);
1527 if (sotcix != SIZE_T_MAX) {
1528 net_qos_dscp_map->sotc_to_dscp[sotcix] =
1529 netsvctype_dscp_map[netsvctype].dscp;
1530 }
1531 break;
1532 }
1533 case NET_SERVICE_TYPE_SIG:
1534 /* Signaling does not have its own traffic class */
1535 break;
1536 default:
1537 /* We should not be here */
1538 ASSERT(0);
1539 }
1540 }
1541 /* Network control socket traffic class is always best effort */
1542 net_qos_dscp_map->sotc_to_dscp[SOTCIX_CTL] = _DSCP_DF;
1543
1544 /* Backround socket traffic class DSCP same as backround system */
1545 net_qos_dscp_map->sotc_to_dscp[SOTCIX_BK] =
1546 net_qos_dscp_map->sotc_to_dscp[SOTCIX_BK_SYS];
1547
1548 return 0;
1549 }
1550
1551 /*
1552 * out_count is an input/ouput parameter
1553 */
1554 static errno_t
1555 get_netsvctype_dscp_map(size_t *out_count,
1556 struct netsvctype_dscp_map *netsvctype_dscp_map)
1557 {
1558 size_t i;
1559 struct net_qos_dscp_map *net_qos_dscp_map = NULL;
1560
1561 /*
1562 * Do not accept more that max number of distinct DSCPs
1563 */
1564 if (out_count == NULL || netsvctype_dscp_map == NULL) {
1565 return EINVAL;
1566 }
1567 if (*out_count > _MAX_DSCP) {
1568 return EINVAL;
1569 }
1570
1571 net_qos_dscp_map = &default_net_qos_dscp_map;
1572
1573 for (i = 0; i < MIN(_NET_SERVICE_TYPE_COUNT, *out_count); i++) {
1574 netsvctype_dscp_map[i].netsvctype = i;
1575 netsvctype_dscp_map[i].dscp = net_qos_dscp_map->netsvctype_to_dscp[i];
1576 }
1577 *out_count = i;
1578
1579 return 0;
1580 }
1581
1582 void
1583 net_qos_map_init()
1584 {
1585 errno_t error;
1586
1587 /*
1588 * By default use the Fastlane DSCP mappngs
1589 */
1590 error = set_netsvctype_dscp_map(_NET_SERVICE_TYPE_COUNT,
1591 fastlane_netsvctype_dscp_map);
1592 ASSERT(error == 0);
1593
1594 /*
1595 * No DSCP mapping for network control
1596 */
1597 default_net_qos_dscp_map.sotc_to_dscp[SOTCIX_CTL] = _DSCP_DF;
1598
1599 set_dscp_to_wifi_ac_map(default_dscp_to_wifi_ac_map, 1);
1600 }
1601
1602 int
1603 sysctl_default_netsvctype_to_dscp_map SYSCTL_HANDLER_ARGS
1604 {
1605 #pragma unused(oidp, arg1, arg2)
1606 int error = 0;
1607 const size_t max_netsvctype_to_dscp_map_len =
1608 _NET_SERVICE_TYPE_COUNT * sizeof(struct netsvctype_dscp_map);
1609 size_t len;
1610 struct netsvctype_dscp_map netsvctype_dscp_map[_NET_SERVICE_TYPE_COUNT] = {};
1611 size_t count;
1612
1613 if (req->oldptr == USER_ADDR_NULL) {
1614 req->oldidx =
1615 _NET_SERVICE_TYPE_COUNT * sizeof(struct netsvctype_dscp_map);
1616 } else if (req->oldlen > 0) {
1617 count = _NET_SERVICE_TYPE_COUNT;
1618 error = get_netsvctype_dscp_map(&count, netsvctype_dscp_map);
1619 if (error != 0) {
1620 goto done;
1621 }
1622 len = count * sizeof(struct netsvctype_dscp_map);
1623 error = SYSCTL_OUT(req, netsvctype_dscp_map,
1624 MIN(len, req->oldlen));
1625 if (error != 0) {
1626 goto done;
1627 }
1628 }
1629
1630 if (req->newptr == USER_ADDR_NULL) {
1631 goto done;
1632 }
1633
1634 error = proc_suser(current_proc());
1635 if (error != 0) {
1636 goto done;
1637 }
1638
1639 /*
1640 * Check input length
1641 */
1642 if (req->newlen > max_netsvctype_to_dscp_map_len) {
1643 error = EINVAL;
1644 goto done;
1645 }
1646 /*
1647 * Cap the number of entries to copy from input buffer
1648 */
1649 error = SYSCTL_IN(req, netsvctype_dscp_map, req->newlen);
1650 if (error != 0) {
1651 goto done;
1652 }
1653
1654 count = req->newlen / sizeof(struct netsvctype_dscp_map);
1655 error = set_netsvctype_dscp_map(count, netsvctype_dscp_map);
1656 done:
1657 return error;
1658 }
1659
1660 __private_extern__ errno_t
1661 set_packet_qos(struct mbuf *m, struct ifnet *ifp, boolean_t qos_allowed,
1662 int sotc, int netsvctype, u_int8_t *dscp_inout)
1663 {
1664 if (ifp == NULL || dscp_inout == NULL) {
1665 return EINVAL;
1666 }
1667
1668 if ((ifp->if_eflags &
1669 (IFEF_QOSMARKING_ENABLED | IFEF_QOSMARKING_CAPABLE)) ==
1670 (IFEF_QOSMARKING_ENABLED | IFEF_QOSMARKING_CAPABLE)) {
1671 u_int8_t dscp;
1672
1673 /*
1674 * When on a Fastlane network, IP_TOS/IPV6_TCLASS are no-ops
1675 */
1676 dscp = _DSCP_DF;
1677
1678 /*
1679 * For DSCP use the network service type is specified, otherwise
1680 * use the socket traffic class
1681 *
1682 * When not whitelisted by the policy, set DSCP only for best
1683 * effort and background, and set the mbuf service class to
1684 * best effort as well so the packet will be queued and
1685 * scheduled at a lower priority.
1686 * We still want to prioritize control traffic on the interface
1687 * so we do not change the mbuf service class for SO_TC_CTL
1688 */
1689 if (IS_VALID_NET_SERVICE_TYPE(netsvctype) &&
1690 netsvctype != NET_SERVICE_TYPE_BE) {
1691 dscp = default_net_qos_dscp_map.netsvctype_to_dscp[netsvctype];
1692
1693 if (qos_allowed == FALSE &&
1694 netsvctype != NET_SERVICE_TYPE_BE &&
1695 netsvctype != NET_SERVICE_TYPE_BK) {
1696 dscp = _DSCP_DF;
1697 if (sotc != SO_TC_CTL) {
1698 m_set_service_class(m, MBUF_SC_BE);
1699 }
1700 }
1701 } else if (sotc != SO_TC_UNSPEC) {
1702 size_t sotcix = sotc_index(sotc);
1703 if (sotcix != SIZE_T_MAX) {
1704 dscp = default_net_qos_dscp_map.sotc_to_dscp[sotcix];
1705
1706 if (qos_allowed == FALSE && sotc != SO_TC_BE &&
1707 sotc != SO_TC_BK && sotc != SO_TC_BK_SYS &&
1708 sotc != SO_TC_CTL) {
1709 dscp = _DSCP_DF;
1710 if (sotc != SO_TC_CTL) {
1711 m_set_service_class(m, MBUF_SC_BE);
1712 }
1713 }
1714 }
1715 }
1716 if (net_qos_verbose != 0) {
1717 printf("%s qos_allowed %d sotc %u netsvctype %u dscp %u\n",
1718 __func__, qos_allowed, sotc, netsvctype, dscp);
1719 }
1720
1721 if (*dscp_inout != dscp) {
1722 *dscp_inout = dscp;
1723 }
1724 } else if (*dscp_inout != _DSCP_DF && IFNET_IS_WIFI_INFRA(ifp)) {
1725 mbuf_svc_class_t msc = m_get_service_class(m);
1726
1727 /*
1728 * For WiFi infra, when the mbuf service class is best effort
1729 * and the DSCP is not default, set the service class based
1730 * on DSCP
1731 */
1732 if (msc == MBUF_SC_BE) {
1733 msc = wifi_dscp_to_msc_array[*dscp_inout];
1734
1735 if (msc != MBUF_SC_BE) {
1736 m_set_service_class(m, msc);
1737
1738 if (net_qos_verbose != 0) {
1739 printf("%s set msc %u for dscp %u\n",
1740 __func__, msc, *dscp_inout);
1741 }
1742 }
1743 }
1744 }
1745
1746 return 0;
1747 }
1748
1749 static void
1750 set_dscp_to_wifi_ac_map(const struct dcsp_msc_map *map, int clear)
1751 {
1752 int i;
1753
1754 if (clear) {
1755 bzero(wifi_dscp_to_msc_array, sizeof(wifi_dscp_to_msc_array));
1756 }
1757
1758 for (i = 0; i < DSCP_ARRAY_SIZE; i++) {
1759 const struct dcsp_msc_map *elem = map + i;
1760
1761 if (elem->dscp > _MAX_DSCP || elem->msc == MBUF_SC_UNSPEC) {
1762 break;
1763 }
1764 switch (elem->msc) {
1765 case MBUF_SC_BK_SYS:
1766 case MBUF_SC_BK:
1767 wifi_dscp_to_msc_array[elem->dscp] = MBUF_SC_BK;
1768 break;
1769 default:
1770 case MBUF_SC_BE:
1771 case MBUF_SC_RD:
1772 case MBUF_SC_OAM:
1773 wifi_dscp_to_msc_array[elem->dscp] = MBUF_SC_BE;
1774 break;
1775 case MBUF_SC_AV:
1776 case MBUF_SC_RV:
1777 case MBUF_SC_VI:
1778 wifi_dscp_to_msc_array[elem->dscp] = MBUF_SC_VI;
1779 break;
1780 case MBUF_SC_VO:
1781 case MBUF_SC_CTL:
1782 wifi_dscp_to_msc_array[elem->dscp] = MBUF_SC_VO;
1783 break;
1784 }
1785 }
1786 }
1787
1788 static errno_t
1789 dscp_msc_map_from_netsvctype_dscp_map(struct netsvctype_dscp_map *netsvctype_dscp_map,
1790 size_t count, struct dcsp_msc_map *dcsp_msc_map)
1791 {
1792 errno_t error = 0;
1793 u_int32_t i;
1794
1795 /*
1796 * Validate input parameters
1797 */
1798 for (i = 0; i < count; i++) {
1799 if (!SO_VALID_TC(netsvctype_dscp_map[i].netsvctype)) {
1800 error = EINVAL;
1801 goto done;
1802 }
1803 if (netsvctype_dscp_map[i].dscp > _MAX_DSCP) {
1804 error = EINVAL;
1805 goto done;
1806 }
1807 }
1808
1809 bzero(dcsp_msc_map, DSCP_ARRAY_SIZE * sizeof(struct dcsp_msc_map));
1810
1811 for (i = 0; i < count; i++) {
1812 dcsp_msc_map[i].dscp = netsvctype_dscp_map[i].dscp;
1813 dcsp_msc_map[i].msc = so_tc2msc(netsvctype_dscp_map[i].netsvctype);
1814 }
1815 done:
1816 return error;
1817 }
1818
1819 int
1820 sysctl_dscp_to_wifi_ac_map SYSCTL_HANDLER_ARGS
1821 {
1822 #pragma unused(oidp, arg1, arg2)
1823 int error = 0;
1824 size_t len = DSCP_ARRAY_SIZE * sizeof(struct netsvctype_dscp_map);
1825 struct netsvctype_dscp_map netsvctype_dscp_map[DSCP_ARRAY_SIZE] = {};
1826 struct dcsp_msc_map dcsp_msc_map[DSCP_ARRAY_SIZE];
1827 size_t count;
1828 u_int32_t i;
1829
1830 if (req->oldptr == USER_ADDR_NULL) {
1831 req->oldidx = len;
1832 } else if (req->oldlen > 0) {
1833 for (i = 0; i < DSCP_ARRAY_SIZE; i++) {
1834 netsvctype_dscp_map[i].dscp = i;
1835 netsvctype_dscp_map[i].netsvctype =
1836 so_svc2tc(wifi_dscp_to_msc_array[i]);
1837 }
1838 error = SYSCTL_OUT(req, netsvctype_dscp_map,
1839 MIN(len, req->oldlen));
1840 if (error != 0) {
1841 goto done;
1842 }
1843 }
1844
1845 if (req->newptr == USER_ADDR_NULL) {
1846 goto done;
1847 }
1848
1849 error = proc_suser(current_proc());
1850 if (error != 0) {
1851 goto done;
1852 }
1853
1854 /*
1855 * Check input length
1856 */
1857 if (req->newlen > len) {
1858 error = EINVAL;
1859 goto done;
1860 }
1861 /*
1862 * Cap the number of entries to copy from input buffer
1863 */
1864 if (len > req->newlen) {
1865 len = req->newlen;
1866 }
1867 error = SYSCTL_IN(req, netsvctype_dscp_map, len);
1868 if (error != 0) {
1869 goto done;
1870 }
1871 count = len / sizeof(struct netsvctype_dscp_map);
1872 bzero(dcsp_msc_map, sizeof(dcsp_msc_map));
1873 error = dscp_msc_map_from_netsvctype_dscp_map(netsvctype_dscp_map, count,
1874 dcsp_msc_map);
1875 if (error != 0) {
1876 goto done;
1877 }
1878 set_dscp_to_wifi_ac_map(dcsp_msc_map, 0);
1879 done:
1880 return error;
1881 }
1882
1883 int
1884 sysctl_reset_dscp_to_wifi_ac_map SYSCTL_HANDLER_ARGS
1885 {
1886 #pragma unused(oidp, arg1, arg2)
1887 int error = 0;
1888 int val = 0;
1889
1890 error = sysctl_handle_int(oidp, &val, 0, req);
1891 if (error || !req->newptr) {
1892 return error;
1893 }
1894
1895 set_dscp_to_wifi_ac_map(default_dscp_to_wifi_ac_map, 1);
1896
1897 return 0;
1898 }
1899
1900 /*
1901 * Returns whether a large upload or download transfer should be marked as
1902 * BK service type for network activity. This is a system level
1903 * hint/suggestion to classify application traffic based on statistics
1904 * collected from the current network attachment
1905 *
1906 * Returns 1 for BK and 0 for default
1907 */
1908
1909 int
1910 net_qos_guideline(struct proc *p, struct net_qos_guideline_args *arg,
1911 int *retval)
1912 {
1913 #pragma unused(p)
1914 #define RETURN_USE_BK 1
1915 #define RETURN_USE_DEFAULT 0
1916 struct net_qos_param qos_arg;
1917 struct ifnet *ipv4_primary, *ipv6_primary;
1918 int err = 0;
1919
1920 if (arg->param == USER_ADDR_NULL || retval == NULL ||
1921 arg->param_len != sizeof(qos_arg)) {
1922 return EINVAL;
1923 }
1924 err = copyin(arg->param, (caddr_t) &qos_arg, sizeof(qos_arg));
1925 if (err != 0) {
1926 return err;
1927 }
1928
1929 *retval = RETURN_USE_DEFAULT;
1930 ipv4_primary = ifindex2ifnet[get_primary_ifscope(AF_INET)];
1931 ipv6_primary = ifindex2ifnet[get_primary_ifscope(AF_INET6)];
1932
1933 /*
1934 * If either of the interfaces is in Low Internet mode, enable
1935 * background delay based algorithms on this transfer
1936 */
1937 if (qos_arg.nq_uplink) {
1938 if ((ipv4_primary != NULL &&
1939 (ipv4_primary->if_xflags & IFXF_LOW_INTERNET_UL)) ||
1940 (ipv6_primary != NULL &&
1941 (ipv6_primary->if_xflags & IFXF_LOW_INTERNET_UL))) {
1942 *retval = RETURN_USE_BK;
1943 return 0;
1944 }
1945 } else {
1946 if ((ipv4_primary != NULL &&
1947 (ipv4_primary->if_xflags & IFXF_LOW_INTERNET_DL)) ||
1948 (ipv6_primary != NULL &&
1949 (ipv6_primary->if_xflags & IFXF_LOW_INTERNET_DL))) {
1950 *retval = RETURN_USE_BK;
1951 return 0;
1952 }
1953 }
1954
1955 /*
1956 * Some times IPv4 and IPv6 primary interfaces can be different.
1957 * In this case, if either of them is non-cellular, we should mark
1958 * the transfer as BK as it can potentially get used based on
1959 * the host name resolution
1960 */
1961 if (ipv4_primary != NULL && IFNET_IS_EXPENSIVE(ipv4_primary) &&
1962 ipv6_primary != NULL && IFNET_IS_EXPENSIVE(ipv6_primary)) {
1963 if (qos_arg.nq_use_expensive) {
1964 return 0;
1965 } else {
1966 *retval = RETURN_USE_BK;
1967 return 0;
1968 }
1969 }
1970 if (qos_arg.nq_transfer_size >= 5 * 1024 * 1024) {
1971 *retval = RETURN_USE_BK;
1972 return 0;
1973 }
1974
1975
1976 #undef RETURN_USE_BK
1977 #undef RETURN_USE_DEFAULT
1978 return 0;
1979 }