]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet/mptcp_usrreq.c
xnu-2782.40.9.tar.gz
[apple/xnu.git] / bsd / netinet / mptcp_usrreq.c
CommitLineData
39236c6e 1/*
fe8ab488 2 * Copyright (c) 2012-2014 Apple Inc. All rights reserved.
39236c6e
A
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/param.h>
30#include <sys/systm.h>
31#include <sys/kernel.h>
32#include <sys/socket.h>
33#include <sys/socketvar.h>
34#include <sys/protosw.h>
35#include <sys/mcache.h>
36#include <sys/syslog.h>
37#include <sys/proc.h>
38#include <sys/proc_internal.h>
39#include <sys/resourcevar.h>
40
41#include <net/if.h>
42#include <netinet/in.h>
43#include <netinet/in_var.h>
44#include <netinet/tcp.h>
45#include <netinet/tcp_fsm.h>
46#include <netinet/tcp_seq.h>
47#include <netinet/tcp_var.h>
48#include <netinet/tcp_timer.h>
49#include <netinet/mptcp_var.h>
50#include <netinet/mptcp_timer.h>
51
52#include <mach/sdt.h>
53
54static int mptcp_usr_attach(struct socket *, int, struct proc *);
55static int mptcp_usr_detach(struct socket *);
56static int mptcp_attach(struct socket *, struct proc *);
57static int mptcp_detach(struct socket *, struct mppcb *);
58static int mptcp_connectx(struct mptses *, struct sockaddr_list **,
59 struct sockaddr_list **, struct proc *, uint32_t, associd_t, connid_t *,
60 uint32_t, void *, uint32_t);
61static int mptcp_usr_connectx(struct socket *, struct sockaddr_list **,
62 struct sockaddr_list **, struct proc *, uint32_t, associd_t, connid_t *,
63 uint32_t, void *, uint32_t);
64static int mptcp_getassocids(struct mptses *, uint32_t *, user_addr_t);
65static int mptcp_getconnids(struct mptses *, associd_t, uint32_t *,
66 user_addr_t);
67static int mptcp_getconninfo(struct mptses *, connid_t *, uint32_t *,
68 uint32_t *, int32_t *, user_addr_t, socklen_t *, user_addr_t, socklen_t *,
69 uint32_t *, user_addr_t, uint32_t *);
70static int mptcp_usr_control(struct socket *, u_long, caddr_t, struct ifnet *,
71 struct proc *);
72static int mptcp_disconnectx(struct mptses *, associd_t, connid_t);
fe8ab488 73static int mptcp_usr_disconnect(struct socket *);
39236c6e
A
74static int mptcp_usr_disconnectx(struct socket *, associd_t, connid_t);
75static struct mptses *mptcp_usrclosed(struct mptses *);
76static int mptcp_usr_peeloff(struct socket *, associd_t, struct socket **);
77static int mptcp_peeloff(struct mptses *, associd_t, struct socket **);
78static int mptcp_usr_rcvd(struct socket *, int);
79static int mptcp_usr_send(struct socket *, int, struct mbuf *,
80 struct sockaddr *, struct mbuf *, struct proc *);
81static int mptcp_usr_shutdown(struct socket *);
82static int mptcp_uiotombuf(struct uio *, int, int, uint32_t, struct mbuf **);
83static int mptcp_usr_sosend(struct socket *, struct sockaddr *, struct uio *,
84 struct mbuf *, struct mbuf *, int);
85static int mptcp_usr_socheckopt(struct socket *, struct sockopt *);
86static int mptcp_setopt_apply(struct mptses *, struct mptopt *);
87static int mptcp_setopt(struct mptses *, struct sockopt *);
88static int mptcp_getopt(struct mptses *, struct sockopt *);
89static int mptcp_default_tcp_optval(struct mptses *, struct sockopt *, int *);
90static void mptcp_connorder_helper(struct mptsub *mpts);
91
92struct pr_usrreqs mptcp_usrreqs = {
93 .pru_attach = mptcp_usr_attach,
94 .pru_connectx = mptcp_usr_connectx,
95 .pru_control = mptcp_usr_control,
96 .pru_detach = mptcp_usr_detach,
fe8ab488 97 .pru_disconnect = mptcp_usr_disconnect,
39236c6e
A
98 .pru_disconnectx = mptcp_usr_disconnectx,
99 .pru_peeloff = mptcp_usr_peeloff,
100 .pru_rcvd = mptcp_usr_rcvd,
101 .pru_send = mptcp_usr_send,
102 .pru_shutdown = mptcp_usr_shutdown,
103 .pru_sosend = mptcp_usr_sosend,
104 .pru_soreceive = soreceive,
105 .pru_socheckopt = mptcp_usr_socheckopt,
106};
107
108/*
109 * Attaches an MPTCP control block to a socket.
110 */
111static int
112mptcp_usr_attach(struct socket *mp_so, int proto, struct proc *p)
113{
114#pragma unused(proto)
115 int error;
116
117 VERIFY(sotomppcb(mp_so) == NULL);
118
119 error = mptcp_attach(mp_so, p);
120 if (error != 0)
121 goto out;
122 /*
123 * XXX: adi@apple.com
124 *
125 * Might want to use a different SO_LINGER timeout than TCP's?
126 */
127 if ((mp_so->so_options & SO_LINGER) && mp_so->so_linger == 0)
128 mp_so->so_linger = TCP_LINGERTIME * hz;
129out:
130 return (error);
131}
132
133/*
134 * Detaches an MPTCP control block from a socket.
135 */
136static int
137mptcp_usr_detach(struct socket *mp_so)
138{
139 struct mppcb *mpp = sotomppcb(mp_so);
140 int error = 0;
141
142 VERIFY(mpp != NULL);
143 VERIFY(mpp->mpp_socket != NULL);
144
145 error = mptcp_detach(mp_so, mpp);
146 return (error);
147}
148
149/*
150 * Attach MPTCP protocol to socket, allocating MP control block,
151 * MPTCP session, control block, buffer space, etc.
152 */
153static int
154mptcp_attach(struct socket *mp_so, struct proc *p)
155{
156#pragma unused(p)
157 struct mptses *mpte;
158 struct mptcb *mp_tp;
159 struct mppcb *mpp;
160 int error = 0;
161
162 if (mp_so->so_snd.sb_hiwat == 0 || mp_so->so_rcv.sb_hiwat == 0) {
163 error = soreserve(mp_so, tcp_sendspace, MPTCP_RWIN_MAX);
164 if (error != 0)
165 goto out;
166 }
167
168 /*
169 * MPTCP socket buffers cannot be compressed, due to the
170 * fact that each mbuf chained via m_next is a M_PKTHDR
171 * which carries some MPTCP metadata.
172 */
173 mp_so->so_snd.sb_flags |= SB_NOCOMPRESS;
174 mp_so->so_rcv.sb_flags |= SB_NOCOMPRESS;
175
176 /* Disable socket buffer auto-tuning. */
177 mp_so->so_rcv.sb_flags &= ~SB_AUTOSIZE;
178 mp_so->so_snd.sb_flags &= ~SB_AUTOSIZE;
179
180 if ((error = mp_pcballoc(mp_so, &mtcbinfo)) != 0)
181 goto out;
182
183 mpp = sotomppcb(mp_so);
184 VERIFY(mpp != NULL);
185
186 mpte = mptcp_sescreate(mp_so, mpp);
187 if (mpte == NULL) {
188 mp_pcbdetach(mpp);
189 error = ENOBUFS;
190 goto out;
191 }
192 mp_tp = mpte->mpte_mptcb;
193 VERIFY(mp_tp != NULL);
194
195 MPT_LOCK(mp_tp);
196 mp_tp->mpt_state = MPTCPS_CLOSED;
197 MPT_UNLOCK(mp_tp);
198
199out:
200 return (error);
201}
202
203/*
204 * Called when the socket layer loses its final reference to the socket;
205 * at this point, there is only one case in which we will keep things
206 * around: time wait.
207 */
208static int
209mptcp_detach(struct socket *mp_so, struct mppcb *mpp)
210{
211 struct mptses *mpte;
212 struct mppcbinfo *mppi;
213
214 VERIFY(mp_so->so_pcb == mpp);
215 VERIFY(mpp->mpp_socket == mp_so);
216
217 mppi = mpp->mpp_pcbinfo;
218 VERIFY(mppi != NULL);
219
220 mpte = &((struct mpp_mtp *)mpp)->mpp_ses;
221 VERIFY(mpte->mpte_mppcb == mpp);
222
223 MPTE_LOCK_ASSERT_HELD(mpte); /* same as MP socket lock */
224
225 /*
226 * We are done with this MPTCP socket (it has been closed);
227 * trigger all subflows to be disconnected, if not already,
228 * by initiating the PCB detach sequence (SOF_PCBCLEARING
229 * will be set.)
230 */
231 mp_pcbdetach(mpp);
232
233 (void) mptcp_disconnectx(mpte, ASSOCID_ALL, CONNID_ALL);
234
235 /*
236 * XXX: adi@apple.com
237 *
238 * Here, we would want to handle time wait state.
239 */
240
241 return (0);
242}
243
244/*
245 * Common subroutine to open a MPTCP connection to one of the remote hosts
246 * specified by dst_sl. This includes allocating and establishing a
247 * subflow TCP connection, either initially to establish MPTCP connection,
248 * or to join an existing one. Returns a connection handle upon success.
249 */
250static int
251mptcp_connectx(struct mptses *mpte, struct sockaddr_list **src_sl,
252 struct sockaddr_list **dst_sl, struct proc *p, uint32_t ifscope,
253 associd_t aid, connid_t *pcid, uint32_t flags, void *arg,
254 uint32_t arglen)
255{
256#pragma unused(p, aid, flags, arg, arglen)
257 struct mptsub *mpts;
258 struct socket *mp_so;
259 int error = 0;
260
261 MPTE_LOCK_ASSERT_HELD(mpte); /* same as MP socket lock */
262 mp_so = mpte->mpte_mppcb->mpp_socket;
263
264 VERIFY(dst_sl != NULL && *dst_sl != NULL);
265 VERIFY(pcid != NULL);
266
267 mptcplog((LOG_DEBUG, "%s: mp_so 0x%llx\n", __func__,
268 (u_int64_t)VM_KERNEL_ADDRPERM(mp_so)));
fe8ab488 269
39236c6e
A
270 DTRACE_MPTCP3(connectx, struct mptses *, mpte, associd_t, aid,
271 struct socket *, mp_so);
272
273 mpts = mptcp_subflow_alloc(M_WAITOK);
274 if (mpts == NULL) {
275 error = ENOBUFS;
276 goto out;
277 }
278 MPTS_ADDREF(mpts); /* for this routine */
279
280 if (src_sl != NULL) {
281 mpts->mpts_src_sl = *src_sl;
282 *src_sl = NULL;
283 }
284 mpts->mpts_dst_sl = *dst_sl;
285 *dst_sl = NULL;
286
287 error = mptcp_subflow_add(mpte, mpts, p, ifscope);
288 if (error == 0 && pcid != NULL)
289 *pcid = mpts->mpts_connid;
290
291out:
292 if (mpts != NULL) {
293 if ((error != 0) && (error != EWOULDBLOCK)) {
294 MPTS_LOCK(mpts);
295 if (mpts->mpts_flags & MPTSF_ATTACHED) {
296 MPTS_UNLOCK(mpts);
297 MPTS_REMREF(mpts);
298 mptcp_subflow_del(mpte, mpts, TRUE);
299 return (error);
300 }
301 MPTS_UNLOCK(mpts);
302 }
303 MPTS_REMREF(mpts);
304 }
305
306 return (error);
307}
308
309/*
310 * User-protocol pru_connectx callback.
311 */
312static int
313mptcp_usr_connectx(struct socket *mp_so, struct sockaddr_list **src_sl,
314 struct sockaddr_list **dst_sl, struct proc *p, uint32_t ifscope,
315 associd_t aid, connid_t *pcid, uint32_t flags, void *arg,
316 uint32_t arglen)
317{
318#pragma unused(arg, arglen)
319 struct mppcb *mpp = sotomppcb(mp_so);
320 struct mptses *mpte;
321 int error = 0;
322
323 if (mpp == NULL || mpp->mpp_state == MPPCB_STATE_DEAD) {
324 error = EINVAL;
325 goto out;
326 }
327 mpte = mptompte(mpp);
328 VERIFY(mpte != NULL);
329
330 error = mptcp_connectx(mpte, src_sl, dst_sl, p, ifscope,
331 aid, pcid, flags, arg, arglen);
332out:
333 return (error);
334}
335
336/*
337 * Handle SIOCGASSOCIDS ioctl for PF_MULTIPATH domain.
338 */
339static int
340mptcp_getassocids(struct mptses *mpte, uint32_t *cnt, user_addr_t aidp)
341{
342 MPTE_LOCK_ASSERT_HELD(mpte); /* same as MP socket lock */
343
344 /* MPTCP has at most 1 association */
345 *cnt = (mpte->mpte_associd != ASSOCID_ANY) ? 1 : 0;
346
347 /* just asking how many there are? */
348 if (aidp == USER_ADDR_NULL)
349 return (0);
350
351 return (copyout(&mpte->mpte_associd, aidp,
352 sizeof (mpte->mpte_associd)));
353}
354
355/*
356 * Handle SIOCGCONNIDS ioctl for PF_MULTIPATH domain.
357 */
358static int
359mptcp_getconnids(struct mptses *mpte, associd_t aid, uint32_t *cnt,
360 user_addr_t cidp)
361{
362 struct mptsub *mpts;
363 int error = 0;
364
365 MPTE_LOCK_ASSERT_HELD(mpte); /* same as MP socket lock */
366
367 if (aid != ASSOCID_ANY && aid != ASSOCID_ALL &&
368 aid != mpte->mpte_associd)
369 return (EINVAL);
370
371 *cnt = mpte->mpte_numflows;
372
373 /* just asking how many there are? */
374 if (cidp == USER_ADDR_NULL)
375 return (0);
376
377 TAILQ_FOREACH(mpts, &mpte->mpte_subflows, mpts_entry) {
378 if ((error = copyout(&mpts->mpts_connid, cidp,
379 sizeof (mpts->mpts_connid))) != 0)
380 break;
381
382 cidp += sizeof (mpts->mpts_connid);
383 }
384
385 return (error);
386}
387
388/*
389 * Handle SIOCGCONNINFO ioctl for PF_MULTIPATH domain.
390 */
391static int
392mptcp_getconninfo(struct mptses *mpte, connid_t *cid, uint32_t *flags,
393 uint32_t *ifindex, int32_t *soerror, user_addr_t src, socklen_t *src_len,
394 user_addr_t dst, socklen_t *dst_len, uint32_t *aux_type,
395 user_addr_t aux_data, uint32_t *aux_len)
396{
397#pragma unused(aux_data)
398 struct sockaddr_entry *se;
399 struct ifnet *ifp = NULL;
400 struct mptsub *mpts;
401 int error = 0;
402
403 MPTE_LOCK_ASSERT_HELD(mpte); /* same as MP socket lock */
404
405 if (*cid == CONNID_ALL)
406 return (EINVAL);
407
408 TAILQ_FOREACH(mpts, &mpte->mpte_subflows, mpts_entry) {
409 if (mpts->mpts_connid == *cid || *cid == CONNID_ANY)
410 break;
411 }
412 if (mpts == NULL)
413 return ((*cid == CONNID_ANY) ? ENXIO : EINVAL);
414
415 MPTS_LOCK(mpts);
416 ifp = mpts->mpts_outif;
417 *cid = mpts->mpts_connid;
418 *ifindex = ((ifp != NULL) ? ifp->if_index : 0);
419 *soerror = mpts->mpts_soerror;
420 *flags = 0;
421 if (mpts->mpts_flags & MPTSF_CONNECTING)
422 *flags |= CIF_CONNECTING;
423 if (mpts->mpts_flags & MPTSF_CONNECTED)
424 *flags |= CIF_CONNECTED;
425 if (mpts->mpts_flags & MPTSF_DISCONNECTING)
426 *flags |= CIF_DISCONNECTING;
427 if (mpts->mpts_flags & MPTSF_DISCONNECTED)
428 *flags |= CIF_DISCONNECTED;
429 if (mpts->mpts_flags & MPTSF_BOUND_IF)
430 *flags |= CIF_BOUND_IF;
431 if (mpts->mpts_flags & MPTSF_BOUND_IP)
432 *flags |= CIF_BOUND_IP;
433 if (mpts->mpts_flags & MPTSF_BOUND_PORT)
434 *flags |= CIF_BOUND_PORT;
435 if (mpts->mpts_flags & MPTSF_PREFERRED)
436 *flags |= CIF_PREFERRED;
437 if (mpts->mpts_flags & MPTSF_MP_CAPABLE)
438 *flags |= CIF_MP_CAPABLE;
439 if (mpts->mpts_flags & MPTSF_MP_DEGRADED)
440 *flags |= CIF_MP_DEGRADED;
441 if (mpts->mpts_flags & MPTSF_MP_READY)
442 *flags |= CIF_MP_READY;
443 if (mpts->mpts_flags & MPTSF_ACTIVE)
444 *flags |= CIF_MP_ACTIVE;
445
446 VERIFY(mpts->mpts_src_sl != NULL);
447 se = TAILQ_FIRST(&mpts->mpts_src_sl->sl_head);
448 VERIFY(se != NULL && se->se_addr != NULL);
449 *src_len = se->se_addr->sa_len;
450 if (src != USER_ADDR_NULL) {
451 error = copyout(se->se_addr, src, se->se_addr->sa_len);
452 if (error != 0)
453 goto out;
454 }
455
456 VERIFY(mpts->mpts_dst_sl != NULL);
457 se = TAILQ_FIRST(&mpts->mpts_dst_sl->sl_head);
458 VERIFY(se != NULL && se->se_addr != NULL);
459 *dst_len = se->se_addr->sa_len;
460 if (dst != USER_ADDR_NULL) {
461 error = copyout(se->se_addr, dst, se->se_addr->sa_len);
462 if (error != 0)
463 goto out;
464 }
465
466 *aux_type = 0;
467 *aux_len = 0;
468 if (mpts->mpts_socket != NULL) {
469 struct conninfo_tcp tcp_ci;
470
471 *aux_type = CIAUX_TCP;
472 *aux_len = sizeof (tcp_ci);
473
474 if (aux_data != USER_ADDR_NULL) {
475 struct socket *so = mpts->mpts_socket;
476
477 VERIFY(SOCK_PROTO(so) == IPPROTO_TCP);
478 bzero(&tcp_ci, sizeof (tcp_ci));
479 socket_lock(so, 0);
480 tcp_getconninfo(so, &tcp_ci);
481 socket_unlock(so, 0);
482 error = copyout(&tcp_ci, aux_data, sizeof (tcp_ci));
483 if (error != 0)
484 goto out;
485 }
486 }
fe8ab488
A
487 mptcplog2((LOG_INFO, "%s: cid %d flags %x \n",
488 __func__, mpts->mpts_connid, mpts->mpts_flags));
39236c6e
A
489out:
490 MPTS_UNLOCK(mpts);
491 return (error);
492}
493
494/*
495 * Handle SIOCSCONNORDER
496 */
497int
498mptcp_setconnorder(struct mptses *mpte, connid_t cid, uint32_t rank)
499{
500 struct mptsub *mpts, *mpts1;
501 int error = 0;
502
503 MPTE_LOCK_ASSERT_HELD(mpte); /* same as MP socket lock */
504 mptcplog((LOG_DEBUG, "%s: cid %d rank %d \n", __func__, cid, rank));
505
506 if (cid == CONNID_ANY || cid == CONNID_ALL) {
507 error = EINVAL;
508 goto out;
509 }
510
511 TAILQ_FOREACH(mpts, &mpte->mpte_subflows, mpts_entry) {
512 if (mpts->mpts_connid == cid)
513 break;
514 }
515 if (mpts == NULL) {
516 error = ENXIO;
517 goto out;
518 }
519
520 if (rank == 0 || rank > 1) {
521 /*
522 * If rank is 0, determine whether this should be the
523 * primary or backup subflow, depending on what we have.
524 *
525 * Otherwise, if greater than 0, make it a backup flow.
526 */
527 TAILQ_FOREACH(mpts1, &mpte->mpte_subflows, mpts_entry) {
528 MPTS_LOCK(mpts1);
529 if (mpts1->mpts_flags & MPTSF_PREFERRED) {
530 MPTS_UNLOCK(mpts1);
531 break;
532 }
533 MPTS_UNLOCK(mpts1);
534 }
535
536 MPTS_LOCK(mpts);
537 mpts->mpts_flags &= ~MPTSF_PREFERRED;
538 mpts->mpts_rank = rank;
539 if (mpts1 != NULL && mpts != mpts1) {
540 /* preferred subflow found; set rank as necessary */
541 if (rank == 0)
542 mpts->mpts_rank = (mpts1->mpts_rank + 1);
543 } else if (rank == 0) {
544 /* no preferred one found; promote this */
545 rank = 1;
546 }
547 MPTS_UNLOCK(mpts);
548 }
549
550 if (rank == 1) {
551 /*
552 * If rank is 1, promote this subflow to be preferred.
553 */
554 TAILQ_FOREACH(mpts1, &mpte->mpte_subflows, mpts_entry) {
555 MPTS_LOCK(mpts1);
556 if (mpts1 != mpts &&
557 (mpts1->mpts_flags & MPTSF_PREFERRED)) {
558 mpts1->mpts_flags &= ~MPTSF_PREFERRED;
fe8ab488 559 if (mpte->mpte_nummpcapflows > 1)
39236c6e
A
560 mptcp_connorder_helper(mpts1);
561 } else if (mpts1 == mpts) {
562 mpts1->mpts_rank = 1;
563 if (mpts1->mpts_flags & MPTSF_MP_CAPABLE) {
564 mpts1->mpts_flags |= MPTSF_PREFERRED;
565 if (mpte->mpte_nummpcapflows > 1)
566 mptcp_connorder_helper(mpts1);
567 }
568 }
569 MPTS_UNLOCK(mpts1);
570 }
571 }
572
573out:
574 return (error);
575}
576
577static void
578mptcp_connorder_helper(struct mptsub *mpts)
579{
580 struct socket *so = mpts->mpts_socket;
581 struct tcpcb *tp = NULL;
582
583 socket_lock(so, 0);
584
585 tp = intotcpcb(sotoinpcb(so));
586 tp->t_mpflags |= TMPF_SND_MPPRIO;
587 if (mpts->mpts_flags & MPTSF_PREFERRED)
588 tp->t_mpflags &= ~TMPF_BACKUP_PATH;
589 else
590 tp->t_mpflags |= TMPF_BACKUP_PATH;
591 mptcplog((LOG_DEBUG, "%s cid %d flags %x", __func__,
592 mpts->mpts_connid, mpts->mpts_flags));
593 socket_unlock(so, 0);
594
595}
596
597/*
598 * Handle SIOCSGONNORDER
599 */
600int
601mptcp_getconnorder(struct mptses *mpte, connid_t cid, uint32_t *rank)
602{
603 struct mptsub *mpts;
604 int error = 0;
605
606 MPTE_LOCK_ASSERT_HELD(mpte); /* same as MP socket lock */
607 VERIFY(rank != NULL);
608 *rank = 0;
609
610 if (cid == CONNID_ANY || cid == CONNID_ALL) {
611 error = EINVAL;
612 goto out;
613 }
614
615 TAILQ_FOREACH(mpts, &mpte->mpte_subflows, mpts_entry) {
616 if (mpts->mpts_connid == cid)
617 break;
618 }
619 if (mpts == NULL) {
620 error = ENXIO;
621 goto out;
622 }
623
624 MPTS_LOCK(mpts);
625 *rank = mpts->mpts_rank;
626 MPTS_UNLOCK(mpts);
627out:
628 return (error);
629}
630
631/*
632 * User-protocol pru_control callback.
633 */
634static int
635mptcp_usr_control(struct socket *mp_so, u_long cmd, caddr_t data,
636 struct ifnet *ifp, struct proc *p)
637{
638#pragma unused(ifp, p)
639 struct mppcb *mpp = sotomppcb(mp_so);
640 struct mptses *mpte;
641 int error = 0;
642
643 if (mpp == NULL || mpp->mpp_state == MPPCB_STATE_DEAD) {
644 error = EINVAL;
645 goto out;
646 }
647 mpte = mptompte(mpp);
648 VERIFY(mpte != NULL);
649
650 MPTE_LOCK_ASSERT_HELD(mpte); /* same as MP socket lock */
651
652 switch (cmd) {
653 case SIOCGASSOCIDS32: { /* struct so_aidreq32 */
654 struct so_aidreq32 aidr;
655 bcopy(data, &aidr, sizeof (aidr));
656 error = mptcp_getassocids(mpte, &aidr.sar_cnt,
657 aidr.sar_aidp);
658 if (error == 0)
659 bcopy(&aidr, data, sizeof (aidr));
660 break;
661 }
662
663 case SIOCGASSOCIDS64: { /* struct so_aidreq64 */
664 struct so_aidreq64 aidr;
665 bcopy(data, &aidr, sizeof (aidr));
666 error = mptcp_getassocids(mpte, &aidr.sar_cnt,
667 aidr.sar_aidp);
668 if (error == 0)
669 bcopy(&aidr, data, sizeof (aidr));
670 break;
671 }
672
673 case SIOCGCONNIDS32: { /* struct so_cidreq32 */
674 struct so_cidreq32 cidr;
675 bcopy(data, &cidr, sizeof (cidr));
676 error = mptcp_getconnids(mpte, cidr.scr_aid, &cidr.scr_cnt,
677 cidr.scr_cidp);
678 if (error == 0)
679 bcopy(&cidr, data, sizeof (cidr));
680 break;
681 }
682
683 case SIOCGCONNIDS64: { /* struct so_cidreq64 */
684 struct so_cidreq64 cidr;
685 bcopy(data, &cidr, sizeof (cidr));
686 error = mptcp_getconnids(mpte, cidr.scr_aid, &cidr.scr_cnt,
687 cidr.scr_cidp);
688 if (error == 0)
689 bcopy(&cidr, data, sizeof (cidr));
690 break;
691 }
692
693 case SIOCGCONNINFO32: { /* struct so_cinforeq32 */
694 struct so_cinforeq32 cifr;
695 bcopy(data, &cifr, sizeof (cifr));
696 error = mptcp_getconninfo(mpte, &cifr.scir_cid,
697 &cifr.scir_flags, &cifr.scir_ifindex, &cifr.scir_error,
698 cifr.scir_src, &cifr.scir_src_len, cifr.scir_dst,
699 &cifr.scir_dst_len, &cifr.scir_aux_type, cifr.scir_aux_data,
700 &cifr.scir_aux_len);
701 if (error == 0)
702 bcopy(&cifr, data, sizeof (cifr));
703 break;
704 }
705
706 case SIOCGCONNINFO64: { /* struct so_cinforeq64 */
707 struct so_cinforeq64 cifr;
708 bcopy(data, &cifr, sizeof (cifr));
709 error = mptcp_getconninfo(mpte, &cifr.scir_cid,
710 &cifr.scir_flags, &cifr.scir_ifindex, &cifr.scir_error,
711 cifr.scir_src, &cifr.scir_src_len, cifr.scir_dst,
712 &cifr.scir_dst_len, &cifr.scir_aux_type, cifr.scir_aux_data,
713 &cifr.scir_aux_len);
714 if (error == 0)
715 bcopy(&cifr, data, sizeof (cifr));
716 break;
717 }
718
719 case SIOCSCONNORDER: { /* struct so_cordreq */
720 struct so_cordreq cor;
721 bcopy(data, &cor, sizeof (cor));
722 error = mptcp_setconnorder(mpte, cor.sco_cid, cor.sco_rank);
723 if (error == 0)
724 bcopy(&cor, data, sizeof (cor));
725 break;
726 }
727
728 case SIOCGCONNORDER: { /* struct so_cordreq */
729 struct so_cordreq cor;
730 bcopy(data, &cor, sizeof (cor));
731 error = mptcp_getconnorder(mpte, cor.sco_cid, &cor.sco_rank);
732 if (error == 0)
733 bcopy(&cor, data, sizeof (cor));
734 break;
735 }
736
737 default:
738 error = EOPNOTSUPP;
739 break;
740 }
741out:
742 return (error);
743}
744
745/*
746 * Initiate a disconnect. MPTCP-level disconnection is specified by
747 * CONNID_{ANY,ALL}. Otherwise, selectively disconnect a subflow
748 * connection while keeping the MPTCP-level connection (association).
749 */
750static int
751mptcp_disconnectx(struct mptses *mpte, associd_t aid, connid_t cid)
752{
753 struct mptsub *mpts;
754 struct socket *mp_so;
755 struct mptcb *mp_tp;
756 int error = 0;
757
758 MPTE_LOCK_ASSERT_HELD(mpte); /* same as MP socket lock */
759
760 mp_so = mpte->mpte_mppcb->mpp_socket;
761 mp_tp = mpte->mpte_mptcb;
762
fe8ab488
A
763 mptcplog((LOG_DEBUG, "%s: mp_so 0x%llx aid %d cid %d %d\n", __func__,
764 (u_int64_t)VM_KERNEL_ADDRPERM(mp_so), aid, cid, mp_so->so_error));
39236c6e
A
765 DTRACE_MPTCP5(disconnectx, struct mptses *, mpte, associd_t, aid,
766 connid_t, cid, struct socket *, mp_so, struct mptcb *, mp_tp);
767
768 VERIFY(aid == ASSOCID_ANY || aid == ASSOCID_ALL ||
769 aid == mpte->mpte_associd);
770
771 /* terminate the association? */
772 if (cid == CONNID_ANY || cid == CONNID_ALL) {
773 /* if we're not detached, go thru socket state checks */
774 if (!(mp_so->so_flags & SOF_PCBCLEARING)) {
775 if (!(mp_so->so_state & (SS_ISCONNECTED|
776 SS_ISCONNECTING))) {
777 error = ENOTCONN;
778 goto out;
779 }
780 if (mp_so->so_state & SS_ISDISCONNECTING) {
781 error = EALREADY;
782 goto out;
783 }
784 }
785 MPT_LOCK(mp_tp);
786 mptcp_cancel_all_timers(mp_tp);
787 if (mp_tp->mpt_state < MPTCPS_ESTABLISHED) {
788 (void) mptcp_close(mpte, mp_tp);
789 MPT_UNLOCK(mp_tp);
790 } else if ((mp_so->so_options & SO_LINGER) &&
791 mp_so->so_linger == 0) {
792 (void) mptcp_drop(mpte, mp_tp, 0);
793 MPT_UNLOCK(mp_tp);
794 } else {
795 MPT_UNLOCK(mp_tp);
796 soisdisconnecting(mp_so);
797 sbflush(&mp_so->so_rcv);
798 if (mptcp_usrclosed(mpte) != NULL)
799 (void) mptcp_output(mpte);
800 }
801 } else {
802 TAILQ_FOREACH(mpts, &mpte->mpte_subflows, mpts_entry) {
803 if (mpts->mpts_connid != cid)
804 continue;
805 MPTS_LOCK(mpts);
fe8ab488 806 mpts->mpts_flags |= MPTSF_USER_DISCONNECT;
39236c6e
A
807 mptcp_subflow_disconnect(mpte, mpts, FALSE);
808 MPTS_UNLOCK(mpts);
809 break;
810 }
811
812 if (mpts == NULL) {
813 error = EINVAL;
814 goto out;
815 }
816 }
817
818 if (error == 0)
819 mptcp_thread_signal(mpte);
820
821 if ((mp_so->so_state & (SS_CANTRCVMORE | SS_CANTSENDMORE)) ==
822 (SS_CANTRCVMORE | SS_CANTSENDMORE)) {
823 /* the socket has been shutdown, no more sockopt's */
824 mptcp_flush_sopts(mpte);
825 }
826
827out:
828 return (error);
829}
830
fe8ab488
A
831/*
832 * Wrapper function to support disconnect on socket
833 */
834static int
835mptcp_usr_disconnect(struct socket *mp_so)
836{
837 int error = 0;
838
839 error = mptcp_usr_disconnectx(mp_so, ASSOCID_ALL, CONNID_ALL);
840 return (error);
841}
842
39236c6e
A
843/*
844 * User-protocol pru_disconnectx callback.
845 */
846static int
847mptcp_usr_disconnectx(struct socket *mp_so, associd_t aid, connid_t cid)
848{
849 struct mppcb *mpp = sotomppcb(mp_so);
850 struct mptses *mpte;
851 int error = 0;
852
853 if (mpp == NULL || mpp->mpp_state == MPPCB_STATE_DEAD) {
854 error = EINVAL;
855 goto out;
856 }
857 mpte = mptompte(mpp);
858 VERIFY(mpte != NULL);
859 MPTE_LOCK_ASSERT_HELD(mpte); /* same as MP socket lock */
860
861 if (aid != ASSOCID_ANY && aid != ASSOCID_ALL &&
862 aid != mpte->mpte_associd) {
863 error = EINVAL;
864 goto out;
865 }
866
867 error = mptcp_disconnectx(mpte, aid, cid);
868out:
869 return (error);
870}
871
872/*
873 * User issued close, and wish to trail thru shutdown states.
874 */
875static struct mptses *
876mptcp_usrclosed(struct mptses *mpte)
877{
878 struct socket *mp_so;
879 struct mptcb *mp_tp;
880 struct mptsub *mpts;
881
882 MPTE_LOCK_ASSERT_HELD(mpte); /* same as MP socket lock */
883 mp_so = mpte->mpte_mppcb->mpp_socket;
884 mp_tp = mpte->mpte_mptcb;
885
886 MPT_LOCK(mp_tp);
887 mptcp_close_fsm(mp_tp, MPCE_CLOSE);
888
fe8ab488 889 if (mp_tp->mpt_state == MPTCPS_CLOSED) {
39236c6e
A
890 mpte = mptcp_close(mpte, mp_tp);
891 MPT_UNLOCK(mp_tp);
892 } else if (mp_tp->mpt_state >= MPTCPS_FIN_WAIT_2) {
893 MPT_UNLOCK(mp_tp);
894 soisdisconnected(mp_so);
fe8ab488
A
895 TAILQ_FOREACH(mpts, &mpte->mpte_subflows, mpts_entry) {
896 MPTS_LOCK(mpts);
897 mpts->mpts_flags |= MPTSF_USER_DISCONNECT;
898 MPTS_UNLOCK(mpts);
899 }
39236c6e 900 } else {
39236c6e
A
901 MPT_UNLOCK(mp_tp);
902
903 TAILQ_FOREACH(mpts, &mpte->mpte_subflows, mpts_entry) {
904 MPTS_LOCK(mpts);
fe8ab488 905 mpts->mpts_flags |= MPTSF_USER_DISCONNECT;
39236c6e
A
906 mptcp_subflow_disconnect(mpte, mpts, FALSE);
907 MPTS_UNLOCK(mpts);
908 }
909 }
39236c6e
A
910
911 return (mpte);
912}
913
914/*
915 * User-protocol pru_peeloff callback.
916 */
917static int
918mptcp_usr_peeloff(struct socket *mp_so, associd_t aid, struct socket **psop)
919{
920 struct mppcb *mpp = sotomppcb(mp_so);
921 struct mptses *mpte;
922 int error = 0;
923
924 VERIFY(psop != NULL);
925
926 if (mpp == NULL || mpp->mpp_state == MPPCB_STATE_DEAD) {
927 error = EINVAL;
928 goto out;
929 }
930 mpte = mptompte(mpp);
931 VERIFY(mpte != NULL);
932
933 error = mptcp_peeloff(mpte, aid, psop);
934out:
935 return (error);
936}
937
938/*
939 * Transform a previously connected TCP subflow connection which has
940 * failed to negotiate MPTCP to its own socket which can be externalized
941 * with a file descriptor. Valid only when the MPTCP socket is not
942 * yet associated (MPTCP-level connection has not been established.)
943 */
944static int
945mptcp_peeloff(struct mptses *mpte, associd_t aid, struct socket **psop)
946{
947 struct socket *so = NULL, *mp_so;
948 struct mptsub *mpts;
949 int error = 0;
950
951 MPTE_LOCK_ASSERT_HELD(mpte); /* same as MP socket lock */
952 mp_so = mpte->mpte_mppcb->mpp_socket;
953
954 VERIFY(psop != NULL);
955 *psop = NULL;
956
957 DTRACE_MPTCP3(peeloff, struct mptses *, mpte, associd_t, aid,
958 struct socket *, mp_so);
959
960 /* peeloff cannot happen after an association is established */
961 if (mpte->mpte_associd != ASSOCID_ANY) {
962 error = EINVAL;
963 goto out;
964 }
965
966 if (aid != ASSOCID_ANY && aid != ASSOCID_ALL) {
967 error = EINVAL;
968 goto out;
969 }
970
971 TAILQ_FOREACH(mpts, &mpte->mpte_subflows, mpts_entry) {
972 MPTS_LOCK(mpts);
973 if (mpts->mpts_flags & MPTSF_MP_CAPABLE) {
974 panic("%s: so %p is MPTCP capable but mp_so %p "
975 "aid is %d\n", __func__, so, mp_so,
976 mpte->mpte_associd);
977 /* NOTREACHED */
978 }
979 MPTS_ADDREF_LOCKED(mpts); /* for us */
980 so = mpts->mpts_socket;
981 VERIFY(so != NULL);
982 /*
983 * This subflow socket is about to be externalized; make it
984 * appear as if it has the same properties as the MPTCP socket,
985 * undo what's done earlier in mptcp_subflow_add().
986 */
987 mptcp_subflow_sopeeloff(mpte, mpts, so);
988 MPTS_UNLOCK(mpts);
989
990 mptcp_subflow_del(mpte, mpts, FALSE);
991 MPTS_REMREF(mpts); /* ours */
992 /*
993 * XXX adi@apple.com
994 *
995 * Here we need to make sure the subflow socket is not
996 * flow controlled; need to clear both INP_FLOW_CONTROLLED
997 * and INP_FLOW_SUSPENDED on the subflow socket, since
998 * we will no longer be monitoring its events.
999 */
1000 break;
1001 }
1002
1003 if (so == NULL) {
1004 error = EINVAL;
1005 goto out;
1006 }
1007 *psop = so;
1008
1009 mptcplog((LOG_DEBUG, "%s: mp_so 0x%llx\n", __func__,
1010 (u_int64_t)VM_KERNEL_ADDRPERM(mp_so)));
1011out:
1012 return (error);
1013}
1014
1015/*
1016 * After a receive, possible send some update to peer.
1017 */
1018static int
1019mptcp_usr_rcvd(struct socket *mp_so, int flags)
1020{
1021#pragma unused(flags)
1022 struct mppcb *mpp = sotomppcb(mp_so);
1023 struct mptses *mpte;
1024 int error = 0;
1025
1026 if (mpp == NULL || mpp->mpp_state == MPPCB_STATE_DEAD) {
1027 error = EINVAL;
1028 goto out;
1029 }
1030 mpte = mptompte(mpp);
1031 VERIFY(mpte != NULL);
1032
1033 error = mptcp_output(mpte);
1034out:
1035 return (error);
1036}
1037
1038/*
1039 * Do a send by putting data in the output queue.
1040 */
1041static int
1042mptcp_usr_send(struct socket *mp_so, int prus_flags, struct mbuf *m,
1043 struct sockaddr *nam, struct mbuf *control, struct proc *p)
1044{
1045#pragma unused(nam, p)
1046 struct mppcb *mpp = sotomppcb(mp_so);
1047 struct mptses *mpte;
1048 int error = 0;
1049
1050 if (prus_flags & (PRUS_OOB|PRUS_EOF)) {
1051 error = EOPNOTSUPP;
1052 goto out;
1053 }
1054
1055 if (nam != NULL) {
1056 error = EOPNOTSUPP;
1057 goto out;
1058 }
1059
1060 if (control != NULL && control->m_len != 0) {
1061 error = EOPNOTSUPP;
1062 goto out;
1063 }
1064
1065 if (mpp == NULL || mpp->mpp_state == MPPCB_STATE_DEAD) {
1066 error = ECONNRESET;
1067 goto out;
1068 }
1069 mpte = mptompte(mpp);
1070 VERIFY(mpte != NULL);
1071
1072 if (!(mp_so->so_state & SS_ISCONNECTED)) {
1073 error = ENOTCONN;
1074 goto out;
1075 }
1076
1077 mptcp_insert_dsn(mpp, m);
1078 VERIFY(mp_so->so_snd.sb_flags & SB_NOCOMPRESS);
1079 (void) sbappendstream(&mp_so->so_snd, m);
1080 m = NULL;
1081
1082 if (mpte != NULL) {
1083 /*
1084 * XXX: adi@apple.com
1085 *
1086 * PRUS_MORETOCOME could be set, but we don't check it now.
1087 */
1088 error = mptcp_output(mpte);
1089 }
1090
1091out:
1092 if (error) {
1093 if (m != NULL)
1094 m_freem(m);
1095 if (control != NULL)
1096 m_freem(control);
1097 }
1098 return (error);
1099}
1100
1101/*
1102 * Mark the MPTCP connection as being incapable of further output.
1103 */
1104static int
1105mptcp_usr_shutdown(struct socket *mp_so)
1106{
1107 struct mppcb *mpp = sotomppcb(mp_so);
1108 struct mptses *mpte;
1109 int error = 0;
1110
1111 if (mpp == NULL || mpp->mpp_state == MPPCB_STATE_DEAD) {
1112 error = EINVAL;
1113 goto out;
1114 }
1115 mpte = mptompte(mpp);
1116 VERIFY(mpte != NULL);
1117
1118 socantsendmore(mp_so);
1119
1120 mpte = mptcp_usrclosed(mpte);
1121 if (mpte != NULL)
1122 error = mptcp_output(mpte);
1123out:
1124 return (error);
1125}
1126
1127/*
1128 * Copy the contents of uio into a properly sized mbuf chain.
1129 */
1130static int
1131mptcp_uiotombuf(struct uio *uio, int how, int space, uint32_t align,
1132 struct mbuf **top)
1133{
1134 struct mbuf *m, *mb, *nm = NULL, *mtail = NULL;
1135 user_ssize_t resid, tot, len, progress; /* must be user_ssize_t */
1136 int error;
1137
1138 VERIFY(top != NULL && *top == NULL);
1139
1140 /*
1141 * space can be zero or an arbitrary large value bound by
1142 * the total data supplied by the uio.
1143 */
1144 resid = uio_resid(uio);
1145 if (space > 0)
1146 tot = imin(resid, space);
1147 else
1148 tot = resid;
1149
1150 /*
1151 * The smallest unit is a single mbuf with pkthdr.
1152 * We can't align past it.
1153 */
1154 if (align >= MHLEN)
1155 return (EINVAL);
1156
1157 /*
1158 * Give us the full allocation or nothing.
1159 * If space is zero return the smallest empty mbuf.
1160 */
1161 if ((len = tot + align) == 0)
1162 len = 1;
1163
1164 /* Loop and append maximum sized mbufs to the chain tail. */
1165 while (len > 0) {
1166 uint32_t m_needed = 1;
1167
1168 if (njcl > 0 && len > MBIGCLBYTES)
1169 mb = m_getpackets_internal(&m_needed, 1,
1170 how, 1, M16KCLBYTES);
1171 else if (len > MCLBYTES)
1172 mb = m_getpackets_internal(&m_needed, 1,
1173 how, 1, MBIGCLBYTES);
1174 else if (len >= (signed)MINCLSIZE)
1175 mb = m_getpackets_internal(&m_needed, 1,
1176 how, 1, MCLBYTES);
1177 else
1178 mb = m_gethdr(how, MT_DATA);
1179
1180 /* Fail the whole operation if one mbuf can't be allocated. */
1181 if (mb == NULL) {
1182 if (nm != NULL)
1183 m_freem(nm);
1184 return (ENOBUFS);
1185 }
1186
1187 /* Book keeping. */
1188 VERIFY(mb->m_flags & M_PKTHDR);
1189 len -= ((mb->m_flags & M_EXT) ? mb->m_ext.ext_size : MHLEN);
1190 if (mtail != NULL)
1191 mtail->m_next = mb;
1192 else
1193 nm = mb;
1194 mtail = mb;
1195 }
1196
1197 m = nm;
1198 m->m_data += align;
1199
1200 progress = 0;
1201 /* Fill all mbufs with uio data and update header information. */
1202 for (mb = m; mb != NULL; mb = mb->m_next) {
1203 len = imin(M_TRAILINGSPACE(mb), tot - progress);
1204
1205 error = uiomove(mtod(mb, char *), len, uio);
1206 if (error != 0) {
1207 m_freem(m);
1208 return (error);
1209 }
1210
1211 /* each mbuf is M_PKTHDR chained via m_next */
1212 mb->m_len = len;
1213 mb->m_pkthdr.len = len;
1214
1215 progress += len;
1216 }
1217 VERIFY(progress == tot);
1218 *top = m;
1219 return (0);
1220}
1221
1222/*
1223 * MPTCP socket protocol-user socket send routine, derived from sosend().
1224 */
1225static int
1226mptcp_usr_sosend(struct socket *mp_so, struct sockaddr *addr, struct uio *uio,
1227 struct mbuf *top, struct mbuf *control, int flags)
1228{
1229#pragma unused(addr)
1230 int32_t space;
1231 user_ssize_t resid;
1232 int error, sendflags;
1233 struct proc *p = current_proc();
1234 int sblocked = 0;
1235
1236 /* UIO is required for now, due to per-mbuf M_PKTHDR constrains */
1237 if (uio == NULL || top != NULL) {
1238 error = EINVAL;
1239 goto out;
1240 }
1241 resid = uio_resid(uio);
1242
1243 socket_lock(mp_so, 1);
1244 so_update_last_owner_locked(mp_so, p);
1245 so_update_policy(mp_so);
1246
1247 VERIFY(mp_so->so_type == SOCK_STREAM);
1248 VERIFY(!(mp_so->so_flags & SOF_MP_SUBFLOW));
1249
1250 if ((flags & (MSG_OOB|MSG_DONTROUTE|MSG_HOLD|MSG_SEND|MSG_FLUSH)) ||
1251 (mp_so->so_flags & SOF_ENABLE_MSGS)) {
1252 error = EOPNOTSUPP;
1253 socket_unlock(mp_so, 1);
1254 goto out;
1255 }
1256
1257 /*
1258 * In theory resid should be unsigned. However, space must be
1259 * signed, as it might be less than 0 if we over-committed, and we
1260 * must use a signed comparison of space and resid. On the other
1261 * hand, a negative resid causes us to loop sending 0-length
1262 * segments to the protocol.
1263 */
1264 if (resid < 0 || (flags & MSG_EOR) || control != NULL) {
1265 error = EINVAL;
1266 socket_unlock(mp_so, 1);
1267 goto out;
1268 }
1269
1270 OSIncrementAtomicLong(&p->p_stats->p_ru.ru_msgsnd);
1271
1272 do {
1273 error = sosendcheck(mp_so, NULL, resid, 0, 0, flags,
1274 &sblocked, NULL);
1275 if (error != 0)
1276 goto release;
1277
1278 space = sbspace(&mp_so->so_snd);
1279 do {
1280 socket_unlock(mp_so, 0);
1281 /*
1282 * Copy the data from userland into an mbuf chain.
1283 */
1284 error = mptcp_uiotombuf(uio, M_WAITOK, space, 0, &top);
1285 if (error != 0) {
1286 socket_lock(mp_so, 0);
1287 goto release;
1288 }
1289 VERIFY(top != NULL);
1290 space -= resid - uio_resid(uio);
1291 resid = uio_resid(uio);
1292 socket_lock(mp_so, 0);
1293
1294 /*
1295 * Compute flags here, for pru_send and NKEs.
1296 */
1297 sendflags = (resid > 0 && space > 0) ?
1298 PRUS_MORETOCOME : 0;
1299
1300 /*
1301 * Socket filter processing
1302 */
1303 VERIFY(control == NULL);
1304 error = sflt_data_out(mp_so, NULL, &top, &control, 0);
1305 if (error != 0) {
1306 if (error == EJUSTRETURN) {
1307 error = 0;
1308 top = NULL;
1309 /* always free control if any */
1310 }
1311 goto release;
1312 }
1313 if (control != NULL) {
1314 m_freem(control);
1315 control = NULL;
1316 }
1317
1318 /*
1319 * Pass data to protocol.
1320 */
1321 error = (*mp_so->so_proto->pr_usrreqs->pru_send)
1322 (mp_so, sendflags, top, NULL, NULL, p);
1323
1324 top = NULL;
1325 if (error != 0)
1326 goto release;
1327 } while (resid != 0 && space > 0);
1328 } while (resid != 0);
1329
1330release:
1331 if (sblocked)
1332 sbunlock(&mp_so->so_snd, FALSE); /* will unlock socket */
1333 else
1334 socket_unlock(mp_so, 1);
1335out:
1336 if (top != NULL)
1337 m_freem(top);
1338 if (control != NULL)
1339 m_freem(control);
1340
1341 return (error);
1342}
1343
1344/*
1345 * Called to filter SOPT_{SET,GET} for SOL_SOCKET level socket options.
1346 * This routine simply indicates to the caller whether or not to proceed
1347 * further with the given socket option. This is invoked by sosetoptlock()
1348 * and sogetoptlock().
1349 */
1350static int
1351mptcp_usr_socheckopt(struct socket *mp_so, struct sockopt *sopt)
1352{
1353#pragma unused(mp_so)
1354 int error = 0;
1355
1356 VERIFY(sopt->sopt_level == SOL_SOCKET);
1357
1358 /*
1359 * We could check for sopt_dir (set/get) here, but we'll just
1360 * let the caller deal with it as appropriate; therefore the
1361 * following is a superset of the socket options which we
1362 * allow for set/get.
1363 *
1364 * XXX: adi@apple.com
1365 *
1366 * Need to consider the following cases:
1367 *
1368 * a. In the event peeloff(2) occurs on the subflow socket,
1369 * we may want to issue those options which are now
1370 * handled at the MP socket. In that case, we will need
1371 * to record them in mptcp_setopt() so that they can
1372 * be replayed during peeloff.
1373 *
1374 * b. Certain socket options don't have a clear definition
1375 * on the expected behavior post connect(2). At the time
1376 * those options are issued on the MP socket, there may
1377 * be existing subflow sockets that are already connected.
1378 */
1379 switch (sopt->sopt_name) {
1380 case SO_LINGER: /* MP */
1381 case SO_LINGER_SEC: /* MP */
1382 case SO_TYPE: /* MP */
1383 case SO_NREAD: /* MP */
1384 case SO_NWRITE: /* MP */
1385 case SO_ERROR: /* MP */
1386 case SO_SNDBUF: /* MP */
1387 case SO_RCVBUF: /* MP */
1388 case SO_SNDLOWAT: /* MP */
1389 case SO_RCVLOWAT: /* MP */
1390 case SO_SNDTIMEO: /* MP */
1391 case SO_RCVTIMEO: /* MP */
1392 case SO_NKE: /* MP */
1393 case SO_NOSIGPIPE: /* MP */
1394 case SO_NOADDRERR: /* MP */
1395 case SO_LABEL: /* MP */
1396 case SO_PEERLABEL: /* MP */
1397 case SO_DEFUNCTOK: /* MP */
1398 case SO_ISDEFUNCT: /* MP */
1399 case SO_TRAFFIC_CLASS_DBG: /* MP */
1400 /*
1401 * Tell the caller that these options are to be processed.
1402 */
1403 break;
1404
1405 case SO_DEBUG: /* MP + subflow */
1406 case SO_KEEPALIVE: /* MP + subflow */
1407 case SO_USELOOPBACK: /* MP + subflow */
1408 case SO_RANDOMPORT: /* MP + subflow */
1409 case SO_TRAFFIC_CLASS: /* MP + subflow */
1410 case SO_RECV_TRAFFIC_CLASS: /* MP + subflow */
1411 case SO_PRIVILEGED_TRAFFIC_CLASS: /* MP + subflow */
1412 case SO_RECV_ANYIF: /* MP + subflow */
1413 case SO_RESTRICTIONS: /* MP + subflow */
1414 case SO_FLUSH: /* MP + subflow */
fe8ab488
A
1415 case SO_MPTCP_FASTJOIN: /* MP + subflow */
1416 case SO_NOWAKEFROMSLEEP:
39236c6e
A
1417 /*
1418 * Tell the caller that these options are to be processed;
1419 * these will also be recorded later by mptcp_setopt().
1420 *
1421 * NOTE: Only support integer option value for now.
1422 */
1423 if (sopt->sopt_valsize != sizeof (int))
1424 error = EINVAL;
1425 break;
1426
1427 default:
1428 /*
1429 * Tell the caller to stop immediately and return an error.
1430 */
1431 error = ENOPROTOOPT;
1432 break;
1433 }
1434
1435 return (error);
1436}
1437
1438/*
1439 * Issue SOPT_SET for all MPTCP subflows (for integer option values.)
1440 */
1441static int
1442mptcp_setopt_apply(struct mptses *mpte, struct mptopt *mpo)
1443{
1444 struct socket *mp_so;
1445 struct mptsub *mpts;
1446 struct mptopt smpo;
1447 int error = 0;
1448
1449 /* just bail now if this isn't applicable to subflow sockets */
1450 if (!(mpo->mpo_flags & MPOF_SUBFLOW_OK)) {
1451 error = ENOPROTOOPT;
1452 goto out;
1453 }
1454
1455 /*
1456 * Skip those that are handled internally; these options
1457 * should not have been recorded and marked with the
1458 * MPOF_SUBFLOW_OK by mptcp_setopt(), but just in case.
1459 */
1460 if (mpo->mpo_level == SOL_SOCKET &&
1461 (mpo->mpo_name == SO_NOSIGPIPE || mpo->mpo_name == SO_NOADDRERR)) {
1462 error = ENOPROTOOPT;
1463 goto out;
1464 }
1465
1466 MPTE_LOCK_ASSERT_HELD(mpte); /* same as MP socket lock */
1467 mp_so = mpte->mpte_mppcb->mpp_socket;
1468
1469 /*
1470 * Don't bother going further if there's no subflow; mark the option
1471 * with MPOF_INTERIM so that we know whether or not to remove this
1472 * option upon encountering an error while issuing it during subflow
1473 * socket creation.
1474 */
1475 if (mpte->mpte_numflows == 0) {
1476 VERIFY(TAILQ_EMPTY(&mpte->mpte_subflows));
1477 mpo->mpo_flags |= MPOF_INTERIM;
1478 /* return success */
1479 goto out;
1480 }
1481
1482 bzero(&smpo, sizeof (smpo));
1483 smpo.mpo_flags |= MPOF_SUBFLOW_OK;
1484 smpo.mpo_level = mpo->mpo_level;
1485 smpo.mpo_name = mpo->mpo_name;
1486
1487 /* grab exisiting values in case we need to rollback */
1488 TAILQ_FOREACH(mpts, &mpte->mpte_subflows, mpts_entry) {
1489 struct socket *so;
1490
1491 MPTS_LOCK(mpts);
1492 mpts->mpts_flags &= ~(MPTSF_SOPT_OLDVAL|MPTSF_SOPT_INPROG);
1493 mpts->mpts_oldintval = 0;
1494 smpo.mpo_intval = 0;
1495 VERIFY(mpts->mpts_socket != NULL);
1496 so = mpts->mpts_socket;
1497 socket_lock(so, 0);
1498 if (mptcp_subflow_sogetopt(mpte, so, &smpo) == 0) {
1499 mpts->mpts_flags |= MPTSF_SOPT_OLDVAL;
1500 mpts->mpts_oldintval = smpo.mpo_intval;
1501 }
1502 socket_unlock(so, 0);
1503 MPTS_UNLOCK(mpts);
1504 }
1505
1506 /* apply socket option */
1507 TAILQ_FOREACH(mpts, &mpte->mpte_subflows, mpts_entry) {
1508 struct socket *so;
1509
1510 MPTS_LOCK(mpts);
1511 mpts->mpts_flags |= MPTSF_SOPT_INPROG;
1512 VERIFY(mpts->mpts_socket != NULL);
1513 so = mpts->mpts_socket;
1514 socket_lock(so, 0);
1515 error = mptcp_subflow_sosetopt(mpte, so, mpo);
1516 socket_unlock(so, 0);
1517 MPTS_UNLOCK(mpts);
1518 if (error != 0)
1519 break;
1520 }
1521
1522 /* cleanup, and rollback if needed */
1523 TAILQ_FOREACH(mpts, &mpte->mpte_subflows, mpts_entry) {
1524 struct socket *so;
1525
1526 MPTS_LOCK(mpts);
1527 if (!(mpts->mpts_flags & MPTSF_SOPT_INPROG)) {
1528 /* clear in case it's set */
1529 mpts->mpts_flags &= ~MPTSF_SOPT_OLDVAL;
1530 mpts->mpts_oldintval = 0;
1531 MPTS_UNLOCK(mpts);
1532 continue;
1533 }
1534 if (!(mpts->mpts_flags & MPTSF_SOPT_OLDVAL)) {
1535 mpts->mpts_flags &= ~MPTSF_SOPT_INPROG;
1536 VERIFY(mpts->mpts_oldintval == 0);
1537 MPTS_UNLOCK(mpts);
1538 continue;
1539 }
1540 /* error during sosetopt, so roll it back */
1541 if (error != 0) {
1542 VERIFY(mpts->mpts_socket != NULL);
1543 so = mpts->mpts_socket;
1544 socket_lock(so, 0);
1545 smpo.mpo_intval = mpts->mpts_oldintval;
1546 (void) mptcp_subflow_sosetopt(mpte, so, &smpo);
1547 socket_unlock(so, 0);
1548 }
1549 mpts->mpts_oldintval = 0;
1550 mpts->mpts_flags &= ~(MPTSF_SOPT_OLDVAL|MPTSF_SOPT_INPROG);
1551 MPTS_UNLOCK(mpts);
1552 }
1553
1554out:
1555 return (error);
1556}
1557
1558/*
1559 * Handle SOPT_SET for socket options issued on MP socket.
1560 */
1561static int
1562mptcp_setopt(struct mptses *mpte, struct sockopt *sopt)
1563{
1564 int error = 0, optval, level, optname, rec = 1;
1565 struct mptopt smpo, *mpo = NULL;
1566 struct socket *mp_so;
1567 char buf[32];
1568
1569 level = sopt->sopt_level;
1570 optname = sopt->sopt_name;
1571
1572 VERIFY(sopt->sopt_dir == SOPT_SET);
1573 VERIFY(level == SOL_SOCKET || level == IPPROTO_TCP);
1574 MPTE_LOCK_ASSERT_HELD(mpte); /* same as MP socket lock */
1575 mp_so = mpte->mpte_mppcb->mpp_socket;
1576
1577 /*
1578 * Record socket options which are applicable to subflow sockets so
1579 * that we can replay them for new ones; see mptcp_usr_socheckopt()
1580 * for the list of eligible socket-level options.
1581 */
1582 if (level == SOL_SOCKET) {
1583 switch (optname) {
1584 case SO_DEBUG:
1585 case SO_KEEPALIVE:
1586 case SO_USELOOPBACK:
1587 case SO_RANDOMPORT:
1588 case SO_TRAFFIC_CLASS:
1589 case SO_RECV_TRAFFIC_CLASS:
1590 case SO_PRIVILEGED_TRAFFIC_CLASS:
1591 case SO_RECV_ANYIF:
1592 case SO_RESTRICTIONS:
fe8ab488
A
1593 case SO_NOWAKEFROMSLEEP:
1594 case SO_MPTCP_FASTJOIN:
39236c6e
A
1595 /* record it */
1596 break;
1597 case SO_FLUSH:
1598 /* don't record it */
1599 rec = 0;
1600 break;
1601 default:
1602 /* nothing to do; just return success */
1603 goto out;
1604 }
1605 } else {
1606 switch (optname) {
1607 case TCP_NODELAY:
1608 case TCP_RXT_FINDROP:
1609 case TCP_KEEPALIVE:
1610 case TCP_KEEPINTVL:
1611 case TCP_KEEPCNT:
1612 case TCP_CONNECTIONTIMEOUT:
1613 case TCP_RXT_CONNDROPTIME:
1614 case PERSIST_TIMEOUT:
1615 /* eligible; record it */
1616 break;
fe8ab488
A
1617 case TCP_NOTSENT_LOWAT:
1618 /* record at MPTCP level */
1619 error = sooptcopyin(sopt, &optval, sizeof(optval),
1620 sizeof(optval));
1621 if (error)
1622 goto out;
1623 if (optval < 0) {
1624 error = EINVAL;
1625 goto out;
1626 } else {
1627 if (optval == 0) {
1628 mp_so->so_flags &= ~SOF_NOTSENT_LOWAT;
1629 error = mptcp_set_notsent_lowat(mpte,0);
1630 } else {
1631 mp_so->so_flags |= SOF_NOTSENT_LOWAT;
1632 error = mptcp_set_notsent_lowat(mpte,
1633 optval);
1634 }
1635 }
1636 goto out;
39236c6e
A
1637 default:
1638 /* not eligible */
1639 error = ENOPROTOOPT;
1640 goto out;
1641 }
1642 }
1643
1644 if ((error = sooptcopyin(sopt, &optval, sizeof (optval),
1645 sizeof (optval))) != 0)
1646 goto out;
1647
1648 if (rec) {
1649 /* search for an existing one; if not found, allocate */
1650 if ((mpo = mptcp_sopt_find(mpte, sopt)) == NULL)
1651 mpo = mptcp_sopt_alloc(M_WAITOK);
1652
1653 if (mpo == NULL) {
1654 error = ENOBUFS;
1655 } else {
1656 mptcplog((LOG_DEBUG, "%s: mp_so 0x%llx sopt %s "
1657 "val %d %s\n", __func__,
1658 (u_int64_t)VM_KERNEL_ADDRPERM(mp_so),
1659 mptcp_sopt2str(level, optname, buf,
1660 sizeof (buf)), optval,
1661 (mpo->mpo_flags & MPOF_ATTACHED) ?
1662 "updated" : "recorded"));
1663
1664 /* initialize or update, as needed */
1665 mpo->mpo_intval = optval;
1666 if (!(mpo->mpo_flags & MPOF_ATTACHED)) {
1667 mpo->mpo_level = level;
1668 mpo->mpo_name = optname;
1669 mptcp_sopt_insert(mpte, mpo);
1670 }
1671 VERIFY(mpo->mpo_flags & MPOF_ATTACHED);
1672 /* this can be issued on the subflow socket */
1673 mpo->mpo_flags |= MPOF_SUBFLOW_OK;
1674 }
1675 } else {
1676 bzero(&smpo, sizeof (smpo));
1677 mpo = &smpo;
1678 mpo->mpo_flags |= MPOF_SUBFLOW_OK;
1679 mpo->mpo_level = level;
1680 mpo->mpo_name = optname;
1681 mpo->mpo_intval = optval;
1682 }
1683 VERIFY(mpo == NULL || error == 0);
1684
1685 /* issue this socket option on existing subflows */
1686 if (error == 0) {
1687 error = mptcp_setopt_apply(mpte, mpo);
1688 if (error != 0 && (mpo->mpo_flags & MPOF_ATTACHED)) {
1689 VERIFY(mpo != &smpo);
1690 mptcp_sopt_remove(mpte, mpo);
1691 mptcp_sopt_free(mpo);
1692 }
1693 if (mpo == &smpo)
1694 mpo->mpo_flags &= ~MPOF_INTERIM;
1695 }
1696out:
1697 if (error == 0 && mpo != NULL) {
1698 mptcplog((LOG_ERR, "%s: mp_so 0x%llx sopt %s val %d set %s\n",
1699 __func__, (u_int64_t)VM_KERNEL_ADDRPERM(mp_so),
1700 mptcp_sopt2str(level, optname, buf,
1701 sizeof (buf)), optval, (mpo->mpo_flags & MPOF_INTERIM) ?
1702 "pending" : "successful"));
1703 } else if (error != 0) {
1704 mptcplog((LOG_ERR, "%s: mp_so 0x%llx sopt %s can't be issued "
1705 "error %d\n", __func__,
1706 (u_int64_t)VM_KERNEL_ADDRPERM(mp_so), mptcp_sopt2str(level,
1707 optname, buf, sizeof (buf)), error));
1708 }
1709 return (error);
1710}
1711
1712/*
1713 * Handle SOPT_GET for socket options issued on MP socket.
1714 */
1715static int
1716mptcp_getopt(struct mptses *mpte, struct sockopt *sopt)
1717{
1718 int error = 0, optval;
1719
1720 VERIFY(sopt->sopt_dir == SOPT_GET);
1721 MPTE_LOCK_ASSERT_HELD(mpte); /* same as MP socket lock */
1722
1723 /*
1724 * We only handle SOPT_GET for TCP level socket options; we should
1725 * not get here for socket level options since they are already
1726 * handled at the socket layer.
1727 */
1728 if (sopt->sopt_level != IPPROTO_TCP) {
1729 error = ENOPROTOOPT;
1730 goto out;
1731 }
1732
1733 switch (sopt->sopt_name) {
1734 case TCP_NODELAY:
1735 case TCP_RXT_FINDROP:
1736 case TCP_KEEPALIVE:
1737 case TCP_KEEPINTVL:
1738 case TCP_KEEPCNT:
1739 case TCP_CONNECTIONTIMEOUT:
1740 case TCP_RXT_CONNDROPTIME:
1741 case PERSIST_TIMEOUT:
fe8ab488 1742 case TCP_NOTSENT_LOWAT:
39236c6e
A
1743 /* eligible; get the default value just in case */
1744 error = mptcp_default_tcp_optval(mpte, sopt, &optval);
1745 break;
1746 default:
1747 /* not eligible */
1748 error = ENOPROTOOPT;
1749 break;
1750 }
1751
fe8ab488
A
1752 switch (sopt->sopt_name) {
1753 case TCP_NOTSENT_LOWAT:
1754 if (mpte->mpte_mppcb->mpp_socket->so_flags & SOF_NOTSENT_LOWAT)
1755 optval = mptcp_get_notsent_lowat(mpte);
1756 else
1757 optval = 0;
1758 goto out;
1759 }
1760
39236c6e
A
1761 /*
1762 * Search for a previously-issued TCP level socket option and
1763 * return the recorded option value. This assumes that the
1764 * value did not get modified by the lower layer after it was
1765 * issued at setsockopt(2) time. If not found, we'll return
1766 * the default value obtained ealier.
1767 */
1768 if (error == 0) {
1769 struct mptopt *mpo;
1770
1771 if ((mpo = mptcp_sopt_find(mpte, sopt)) != NULL)
1772 optval = mpo->mpo_intval;
1773
1774 error = sooptcopyout(sopt, &optval, sizeof (int));
1775 }
1776out:
1777 return (error);
1778}
1779
1780/*
1781 * Return default values for TCP socket options. Ideally we would query the
1782 * subflow TCP socket, but that requires creating a subflow socket before
1783 * connectx(2) time. To simplify things, just return the default values
1784 * that we know of.
1785 */
1786static int
1787mptcp_default_tcp_optval(struct mptses *mpte, struct sockopt *sopt, int *optval)
1788{
1789 int error = 0;
1790
1791 VERIFY(sopt->sopt_level == IPPROTO_TCP);
1792 VERIFY(sopt->sopt_dir == SOPT_GET);
1793 MPTE_LOCK_ASSERT_HELD(mpte); /* same as MP socket lock */
1794
1795 /* try to do what tcp_newtcpcb() does */
1796 switch (sopt->sopt_name) {
1797 case TCP_NODELAY:
1798 case TCP_RXT_FINDROP:
1799 case TCP_KEEPINTVL:
1800 case TCP_KEEPCNT:
1801 case TCP_CONNECTIONTIMEOUT:
1802 case TCP_RXT_CONNDROPTIME:
fe8ab488 1803 case TCP_NOTSENT_LOWAT:
39236c6e
A
1804 *optval = 0;
1805 break;
1806
1807 case TCP_KEEPALIVE:
1808 *optval = mptcp_subflow_keeptime;
1809 break;
1810
1811 case PERSIST_TIMEOUT:
1812 *optval = tcp_max_persist_timeout;
1813 break;
1814
1815 default:
1816 error = ENOPROTOOPT;
1817 break;
1818 }
1819 return (error);
1820}
1821
1822/*
1823 * MPTCP SOPT_{SET,GET} socket option handler, for options issued on the MP
1824 * socket, at SOL_SOCKET and IPPROTO_TCP levels. The former is restricted
1825 * to those that are allowed by mptcp_usr_socheckopt().
1826 */
1827int
1828mptcp_ctloutput(struct socket *mp_so, struct sockopt *sopt)
1829{
1830 struct mppcb *mpp = sotomppcb(mp_so);
1831 struct mptses *mpte;
1832 int error = 0;
1833
1834 if (mpp == NULL || mpp->mpp_state == MPPCB_STATE_DEAD) {
1835 error = EINVAL;
1836 goto out;
1837 }
1838 mpte = mptompte(mpp);
1839 MPTE_LOCK_ASSERT_HELD(mpte); /* same as MP socket lock */
1840
1841 /* we only handle socket and TCP-level socket options for MPTCP */
1842 if (sopt->sopt_level != SOL_SOCKET && sopt->sopt_level != IPPROTO_TCP) {
1843 char buf[32];
1844 mptcplog((LOG_DEBUG, "%s: mp_so 0x%llx sopt %s level not "
1845 "handled\n", __func__, (u_int64_t)VM_KERNEL_ADDRPERM(mp_so),
1846 mptcp_sopt2str(sopt->sopt_level,
1847 sopt->sopt_name, buf, sizeof (buf))));
1848 error = EINVAL;
1849 goto out;
1850 }
1851
1852 switch (sopt->sopt_dir) {
1853 case SOPT_SET:
1854 error = mptcp_setopt(mpte, sopt);
1855 break;
1856
1857 case SOPT_GET:
1858 error = mptcp_getopt(mpte, sopt);
1859 break;
1860 }
1861out:
1862 return (error);
1863}
1864
1865/*
1866 * Return a string representation of <sopt_level,sopt_name>
1867 */
1868const char *
1869mptcp_sopt2str(int level, int optname, char *dst, int size)
1870{
1871 char lbuf[32], obuf[32];
1872 const char *l = lbuf, *o = obuf;
1873
1874 (void) snprintf(lbuf, sizeof (lbuf), "0x%x", level);
1875 (void) snprintf(obuf, sizeof (obuf), "0x%x", optname);
1876
1877 switch (level) {
1878 case SOL_SOCKET:
1879 l = "SOL_SOCKET";
1880 switch (optname) {
1881 case SO_LINGER:
1882 o = "SO_LINGER";
1883 break;
1884 case SO_LINGER_SEC:
1885 o = "SO_LINGER_SEC";
1886 break;
1887 case SO_DEBUG:
1888 o = "SO_DEBUG";
1889 break;
1890 case SO_KEEPALIVE:
1891 o = "SO_KEEPALIVE";
1892 break;
1893 case SO_USELOOPBACK:
1894 o = "SO_USELOOPBACK";
1895 break;
1896 case SO_TYPE:
1897 o = "SO_TYPE";
1898 break;
1899 case SO_NREAD:
1900 o = "SO_NREAD";
1901 break;
1902 case SO_NWRITE:
1903 o = "SO_NWRITE";
1904 break;
1905 case SO_ERROR:
1906 o = "SO_ERROR";
1907 break;
1908 case SO_SNDBUF:
1909 o = "SO_SNDBUF";
1910 break;
1911 case SO_RCVBUF:
1912 o = "SO_RCVBUF";
1913 break;
1914 case SO_SNDLOWAT:
1915 o = "SO_SNDLOWAT";
1916 break;
1917 case SO_RCVLOWAT:
1918 o = "SO_RCVLOWAT";
1919 break;
1920 case SO_SNDTIMEO:
1921 o = "SO_SNDTIMEO";
1922 break;
1923 case SO_RCVTIMEO:
1924 o = "SO_RCVTIMEO";
1925 break;
1926 case SO_NKE:
1927 o = "SO_NKE";
1928 break;
1929 case SO_NOSIGPIPE:
1930 o = "SO_NOSIGPIPE";
1931 break;
1932 case SO_NOADDRERR:
1933 o = "SO_NOADDRERR";
1934 break;
1935 case SO_RESTRICTIONS:
1936 o = "SO_RESTRICTIONS";
1937 break;
1938 case SO_LABEL:
1939 o = "SO_LABEL";
1940 break;
1941 case SO_PEERLABEL:
1942 o = "SO_PEERLABEL";
1943 break;
1944 case SO_RANDOMPORT:
1945 o = "SO_RANDOMPORT";
1946 break;
1947 case SO_TRAFFIC_CLASS:
1948 o = "SO_TRAFFIC_CLASS";
1949 break;
1950 case SO_RECV_TRAFFIC_CLASS:
1951 o = "SO_RECV_TRAFFIC_CLASS";
1952 break;
1953 case SO_TRAFFIC_CLASS_DBG:
1954 o = "SO_TRAFFIC_CLASS_DBG";
1955 break;
1956 case SO_PRIVILEGED_TRAFFIC_CLASS:
1957 o = "SO_PRIVILEGED_TRAFFIC_CLASS";
1958 break;
1959 case SO_DEFUNCTOK:
1960 o = "SO_DEFUNCTOK";
1961 break;
1962 case SO_ISDEFUNCT:
1963 o = "SO_ISDEFUNCT";
1964 break;
1965 case SO_OPPORTUNISTIC:
1966 o = "SO_OPPORTUNISTIC";
1967 break;
1968 case SO_FLUSH:
1969 o = "SO_FLUSH";
1970 break;
1971 case SO_RECV_ANYIF:
1972 o = "SO_RECV_ANYIF";
1973 break;
fe8ab488
A
1974 case SO_NOWAKEFROMSLEEP:
1975 o = "SO_NOWAKEFROMSLEEP";
1976 break;
1977 case SO_MPTCP_FASTJOIN:
1978 o = "SO_MPTCP_FASTJOIN";
1979 break;
39236c6e
A
1980 }
1981 break;
1982 case IPPROTO_TCP:
1983 l = "IPPROTO_TCP";
1984 switch (optname) {
1985 case TCP_KEEPALIVE:
1986 o = "TCP_KEEPALIVE";
1987 break;
1988 case TCP_KEEPINTVL:
1989 o = "TCP_KEEPINTVL";
1990 break;
1991 case TCP_KEEPCNT:
1992 o = "TCP_KEEPCNT";
1993 break;
1994 case TCP_CONNECTIONTIMEOUT:
1995 o = "TCP_CONNECTIONTIMEOUT";
1996 break;
1997 case TCP_RXT_CONNDROPTIME:
1998 o = "TCP_RXT_CONNDROPTIME";
1999 break;
2000 case PERSIST_TIMEOUT:
2001 o = "PERSIST_TIMEOUT";
2002 break;
2003 }
2004 break;
2005 }
2006
2007 (void) snprintf(dst, size, "<%s,%s>", l, o);
2008 return (dst);
2009}