1 /* $NetBSD: tp_output.c,v 1.38 2009/04/16 22:22:06 elad Exp $ */
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * @(#)tp_output.c 8.2 (Berkeley) 2/9/95
34 /***********************************************************
35 Copyright IBM Corporation 1987
39 Permission to use, copy, modify, and distribute this software and its
40 documentation for any purpose and without fee is hereby granted,
41 provided that the above copyright notice appear in all copies and that
42 both that copyright notice and this permission notice appear in
43 supporting documentation, and that the name of IBM not be
44 used in advertising or publicity pertaining to distribution of the
45 software without specific, written prior permission.
47 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
48 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
49 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
50 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
51 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
52 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
55 ******************************************************************/
58 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
61 * In here is tp_ctloutput(), the guy called by [sg]etsockopt(),
64 #include <sys/cdefs.h>
65 __KERNEL_RCSID(0, "$NetBSD: tp_output.c,v 1.38 2009/04/16 22:22:06 elad Exp $");
70 #include <sys/param.h>
72 #include <sys/systm.h>
73 #include <sys/socket.h>
74 #include <sys/socketvar.h>
75 #include <sys/protosw.h>
76 #include <sys/errno.h>
78 #include <sys/kernel.h>
80 #include <sys/kauth.h>
82 #include <netiso/tp_param.h>
83 #include <netiso/tp_var.h>
84 #include <netiso/tp_user.h>
85 #include <netiso/tp_stat.h>
86 #include <netiso/tp_ip.h>
87 #include <netiso/tp_clnp.h>
88 #include <netiso/tp_timer.h>
89 #include <netiso/argo_debug.h>
90 #include <netiso/tp_pcb.h>
91 #include <netiso/tp_trace.h>
93 #define TPDUSIZESHIFT 24
97 * NAME: tp_consistency()
100 * tp_ctloutput(), tp_input()
102 * FUNCTION and ARGUMENTS:
103 * Checks the consistency of options and tpdusize with class,
104 * using the parameters passed in via (param).
105 * (cmd) may be TP_STRICT or TP_FORCE or both.
106 * Force means it will set all the values in (tpcb) to those in
107 * the input arguments iff no errors were encountered.
108 * Strict means that no inconsistency will be tolerated. If it's
109 * not used, checksum and tpdusize inconsistencies will be tolerated.
110 * The reason for this is that in some cases, when we're negotiating down
111 * from class 4, these options should be changed but should not
112 * cause negotiation to fail.
116 * E* if the various parms aren't ok for a given class
117 * EOK if they are ok for a given class
121 tp_consistency(struct tp_pcb
*tpcb
, u_int cmd
, struct tp_conn_param
*param
)
124 int class_to_use
= tp_mask_to_num(param
->p_class
);
127 if (tp_traceflags
[D_SETPARAMS
]) {
129 "tp_consist enter class_to_use dontchange param.class cmd",
130 class_to_use
, param
->p_dont_change_params
, param
->p_class
, cmd
);
134 if (argo_debug
[D_SETPARAMS
]) {
135 printf("tp_consistency %s %s\n",
136 cmd
& TP_FORCE
? "TP_FORCE" : "",
137 cmd
& TP_STRICT
? "TP_STRICT" : "");
140 if ((cmd
& TP_FORCE
) && (param
->p_dont_change_params
)) {
144 * can switch net services within a domain, but cannot switch domains
146 switch (param
->p_netservice
) {
150 /* param->p_netservice in ISO DOMAIN */
151 if (tpcb
->tp_domain
!= AF_ISO
) {
157 /* param->p_netservice in INET DOMAIN */
158 if (tpcb
->tp_domain
!= AF_INET
) {
163 /* no others not possible-> netservice is a 2-bit field! */
167 if (argo_debug
[D_SETPARAMS
]) {
168 printf("p_class 0x%x, class_to_use 0x%x\n", param
->p_class
,
172 if ((param
->p_netservice
> TP_MAX_NETSERVICES
)) {
176 if ((param
->p_class
& TP_CLASSES_IMPLEMENTED
) == 0) {
181 if (argo_debug
[D_SETPARAMS
]) {
182 printf("Nretrans 0x%x\n", param
->p_Nretrans
);
185 if ((param
->p_Nretrans
< 1) ||
186 (param
->p_cr_ticks
< 1) || (param
->p_cc_ticks
< 1)) {
188 * bad for any class because negot has to be done a la class
195 if (argo_debug
[D_SETPARAMS
]) {
196 printf("use_csum 0x%x\n", param
->p_use_checksum
);
197 printf("xtd_format 0x%x\n", param
->p_xtd_format
);
198 printf("xpd_service 0x%x\n", param
->p_xpd_service
);
199 printf("tpdusize 0x%x\n", param
->p_tpdusize
);
200 printf("tpcb->flags 0x%x\n", tpcb
->tp_flags
);
203 switch (class_to_use
) {
206 /* do not use checksums, xtd format, or XPD */
208 if (param
->p_use_checksum
| param
->p_xtd_format
| param
->p_xpd_service
) {
209 if (cmd
& TP_STRICT
) {
212 param
->p_use_checksum
= 0;
213 param
->p_xtd_format
= 0;
214 param
->p_xpd_service
= 0;
218 if (param
->p_tpdusize
< TP_MIN_TPDUSIZE
) {
219 if (cmd
& TP_STRICT
) {
222 param
->p_tpdusize
= TP_MIN_TPDUSIZE
;
226 if (param
->p_tpdusize
> TP0_TPDUSIZE
) {
227 if (cmd
& TP_STRICT
) {
230 param
->p_tpdusize
= TP0_TPDUSIZE
;
234 /* connect/disc data not allowed for class 0 */
235 if (tpcb
->tp_ucddata
) {
236 if (cmd
& TP_STRICT
) {
238 } else if (cmd
& TP_FORCE
) {
239 m_freem(tpcb
->tp_ucddata
);
240 tpcb
->tp_ucddata
= 0;
247 if (argo_debug
[D_SETPARAMS
]) {
248 printf("dt_ticks 0x%x\n", param
->p_dt_ticks
);
249 printf("x_ticks 0x%x\n", param
->p_x_ticks
);
250 printf("dr_ticks 0x%x\n", param
->p_dr_ticks
);
251 printf("keepalive 0x%x\n", param
->p_keepalive_ticks
);
252 printf("sendack 0x%x\n", param
->p_sendack_ticks
);
253 printf("inact 0x%x\n", param
->p_inact_ticks
);
254 printf("ref 0x%x\n", param
->p_ref_ticks
);
257 if ((param
->p_class
& TP_CLASS_4
) && (
258 (param
->p_dt_ticks
< 1) || (param
->p_dr_ticks
< 1) ||
259 (param
->p_x_ticks
< 1) || (param
->p_keepalive_ticks
< 1) ||
260 (param
->p_sendack_ticks
< 1) || (param
->p_ref_ticks
< 1) ||
261 (param
->p_inact_ticks
< 1))) {
266 if (argo_debug
[D_SETPARAMS
]) {
267 printf("rx_strat 0x%x\n", param
->p_rx_strat
);
270 if (param
->p_rx_strat
>
271 (TPRX_USE_CW
| TPRX_EACH
| TPRX_FASTSTART
)) {
272 if (cmd
& TP_STRICT
) {
275 param
->p_rx_strat
= TPRX_USE_CW
;
280 if (argo_debug
[D_SETPARAMS
]) {
281 printf("ack_strat 0x%x\n", param
->p_ack_strat
);
284 if ((param
->p_ack_strat
!= 0) && (param
->p_ack_strat
!= 1)) {
285 if (cmd
& TP_STRICT
) {
288 param
->p_ack_strat
= TPACK_WINDOW
;
292 if (param
->p_tpdusize
< TP_MIN_TPDUSIZE
) {
293 if (cmd
& TP_STRICT
) {
296 param
->p_tpdusize
= TP_MIN_TPDUSIZE
;
300 if (param
->p_tpdusize
> TP_TPDUSIZE
) {
301 if (cmd
& TP_STRICT
) {
304 param
->p_tpdusize
= TP_TPDUSIZE
;
311 if ((error
== 0) && (cmd
& TP_FORCE
)) {
312 long dusize
= ((long) param
->p_ptpdusize
) << 7;
313 /* Enforce Negotation rules below */
314 tpcb
->tp_class
= param
->p_class
;
315 if (tpcb
->tp_use_checksum
|| param
->p_use_checksum
)
316 tpcb
->tp_use_checksum
= 1;
317 if (!tpcb
->tp_xpd_service
|| !param
->p_xpd_service
)
318 tpcb
->tp_xpd_service
= 0;
319 if (!tpcb
->tp_xtd_format
|| !param
->p_xtd_format
)
320 tpcb
->tp_xtd_format
= 0;
322 if (tpcb
->tp_l_tpdusize
> dusize
)
323 tpcb
->tp_l_tpdusize
= dusize
;
324 if (tpcb
->tp_ptpdusize
== 0 ||
325 tpcb
->tp_ptpdusize
> param
->p_ptpdusize
)
326 tpcb
->tp_ptpdusize
= param
->p_ptpdusize
;
328 if (param
->p_tpdusize
!= 0 &&
329 tpcb
->tp_tpdusize
> param
->p_tpdusize
)
330 tpcb
->tp_tpdusize
= param
->p_tpdusize
;
331 tpcb
->tp_l_tpdusize
= 1 << tpcb
->tp_tpdusize
;
337 if (tp_traceflags
[D_CONN
]) {
338 tptrace(TPPTmisc
, "tp_consist returns class xtdfmt cmd",
339 error
, tpcb
->tp_class
, tpcb
->tp_xtd_format
, cmd
);
343 if (argo_debug
[D_CONN
]) {
345 "tp_consist rtns 0x%x class 0x%x xtd_fmt 0x%x cmd 0x%x\n",
346 error
, tpcb
->tp_class
, tpcb
->tp_xtd_format
, cmd
);
353 * NAME: tp_ctloutput1()
356 * [sg]etsockopt(), via so[sg]etopt().
357 * via tp_ctloutput() below
359 * FUNCTION and ARGUMENTS:
360 * Implements the socket options at transport level.
361 * (cmd) is either PRCO_SETOPT or PRCO_GETOPT (see ../sys/protosw.h).
362 * (so) is the socket.
363 * (level) is SOL_TRANSPORT (see ../sys/socket.h)
364 * (optname) is the particular command or option to be set.
365 * (**mp) is an mbuf structure.
368 * ENOTSOCK if the socket hasn't got an associated tpcb
370 * trying to set window too big
371 * trying to set illegal max tpdu size
372 * trying to set illegal credit fraction
373 * trying to use unknown or unimplemented class of TP
374 * structure passed to set timer values is wrong size
375 * illegal combination of command/GET-SET option,
376 * e.g., GET w/ TPOPT_CDDATA_CLEAR:
377 * EOPNOTSUPP if the level isn't transport, or command is neither GET nor SET
378 * or if the transport-specific command is not implemented
379 * EISCONN if trying a command that isn't allowed after a connection
381 * ENOTCONN if trying a command that is allowed only if a connection is
383 * EMSGSIZE if trying to give too much data on connect/disconnect
390 tp_ctloutput1(int cmd
, struct socket
*so
, int level
, int optname
,
393 struct lwp
*l
= curlwp
; /* XXX */
394 struct tp_pcb
*tpcb
= sototpcb(so
);
395 int s
= splsoftnet();
401 if (tp_traceflags
[D_REQUEST
]) {
402 tptrace(TPPTmisc
, "tp_ctloutput cmd so optname mp",
403 cmd
, so
, optname
, mp
);
407 if (argo_debug
[D_REQUEST
]) {
409 "tp_ctloutput so %p cmd 0x%x optname 0x%x, mp %p *mp %p tpcb %p\n",
410 so
, cmd
, optname
, mp
, mp
? *mp
: 0, tpcb
);
413 if (tpcb
== (struct tp_pcb
*) 0) {
417 if (mp
&& *mp
== NULL
) {
420 MGET(m
, M_DONTWAIT
, TPMT_SONAME
); /* does off, type, next */
430 * Hook so one can set network options via a tp socket.
432 if (level
== SOL_NETWORK
) {
433 if ((tpcb
->tp_nlproto
== NULL
) || (tpcb
->tp_npcb
== NULL
))
435 else if (tpcb
->tp_nlproto
->nlp_ctloutput
== NULL
)
438 return ((tpcb
->tp_nlproto
->nlp_ctloutput
) (cmd
, optname
,
439 tpcb
->tp_npcb
, *mp
));
441 } else if (level
== SOL_SOCKET
) {
442 if (optname
== SO_RCVBUF
&& cmd
== PRCO_SETOPT
) {
443 u_long old_credit
= tpcb
->tp_maxlcredit
;
445 if (tpcb
->tp_rhiwat
!= so
->so_rcv
.sb_hiwat
&&
446 tpcb
->tp_state
== TP_OPEN
&&
447 (old_credit
< tpcb
->tp_maxlcredit
))
448 tp_emit(AK_TPDU_type
, tpcb
,
449 tpcb
->tp_rcvnxt
, 0, NULL
);
450 tpcb
->tp_rhiwat
= so
->so_rcv
.sb_hiwat
;
453 } else if (level
!= SOL_TRANSPORT
) {
457 if (cmd
!= PRCO_GETOPT
&& cmd
!= PRCO_SETOPT
) {
462 error
= so
->so_error
;
466 * The only options allowed after connection is established are GET
467 * (anything) and SET DISC DATA and SET PERF MEAS
469 if (((so
->so_state
& SS_ISCONNECTING
) || (so
->so_state
& SS_ISCONNECTED
))
471 (cmd
== PRCO_SETOPT
&&
472 optname
!= TPOPT_DISC_DATA
&&
473 optname
!= TPOPT_CFRM_DATA
&&
474 optname
!= TPOPT_PERF_MEAS
&&
475 optname
!= TPOPT_CDDATA_CLEAR
)) {
480 * The only options allowed after disconnection are GET DISC DATA,
481 * and TPOPT_PSTATISTICS and they're not allowed if the ref timer has
482 * gone off, because the tpcb is gone
484 if ((so
->so_state
& (SS_ISCONNECTED
| SS_ISCONFIRMING
)) == 0) {
485 if (so
->so_pcb
== 0) {
489 if ((tpcb
->tp_state
== TP_REFWAIT
|| tpcb
->tp_state
== TP_CLOSING
) &&
490 (optname
!= TPOPT_DISC_DATA
&& optname
!= TPOPT_PSTATISTICS
)) {
495 value
= mtod(*mp
, void *); /* it's aligned, don't worry, but
496 * lint complains about it */
497 val_len
= (*mp
)->m_len
;
501 case TPOPT_INTERCEPT
:
502 #define INA(t) (((struct inpcb *)(t->tp_npcb))->inp_laddr.s_addr)
503 #define ISOA(t) (((struct isopcb *)(t->tp_npcb))->isop_laddr->siso_addr)
505 if (l
== NULL
|| (error
= kauth_authorize_network(l
->l_cred
,
506 KAUTH_NETWORK_SOCKET
, KAUTH_REQ_NETWORK_SOCKET_SETPRIV
,
507 KAUTH_ARG(optname
), NULL
, NULL
))) {
509 } else if (cmd
!= PRCO_SETOPT
|| tpcb
->tp_state
!= TP_CLOSED
||
510 (tpcb
->tp_flags
& TPF_GENERAL_ADDR
) ||
516 for (t
= tp_listeners
; t
; t
= t
->tp_nextlisten
)
517 if ((t
->tp_flags
& TPF_GENERAL_ADDR
) == 0 &&
518 t
->tp_domain
== tpcb
->tp_domain
)
519 switch (tpcb
->tp_domain
) {
524 if (INA(t
) == INA(tpcb
))
530 if (memcmp(ISOA(t
).isoa_genaddr
, ISOA(tpcb
).isoa_genaddr
,
531 ISOA(t
).isoa_len
) == 0)
536 tpcb
->tp_lsuffixlen
= 0;
537 tpcb
->tp_state
= TP_LISTENING
;
540 tpcb
->tp_next
= tpcb
->tp_prev
= tpcb
;
541 tpcb
->tp_nextlisten
= tp_listeners
;
547 if (cmd
== PRCO_GETOPT
) {
548 ASSERT(tpcb
->tp_lsuffixlen
<= MAX_TSAP_SEL_LEN
);
549 memcpy(value
, (void *) tpcb
->tp_lsuffix
, tpcb
->tp_lsuffixlen
);
550 (*mp
)->m_len
= tpcb
->tp_lsuffixlen
;
551 } else { /* cmd == PRCO_SETOPT */
552 if ((val_len
> MAX_TSAP_SEL_LEN
) || (val_len
<= 0)) {
553 printf("val_len 0x%x (*mp)->m_len %p\n",
557 memcpy((void *) tpcb
->tp_lsuffix
, value
, val_len
);
558 tpcb
->tp_lsuffixlen
= val_len
;
563 case TPOPT_PEER_TSEL
:
564 if (cmd
== PRCO_GETOPT
) {
565 ASSERT(tpcb
->tp_fsuffixlen
<= MAX_TSAP_SEL_LEN
);
566 memcpy(value
, (void *) tpcb
->tp_fsuffix
, tpcb
->tp_fsuffixlen
);
567 (*mp
)->m_len
= tpcb
->tp_fsuffixlen
;
568 } else { /* cmd == PRCO_SETOPT */
569 if ((val_len
> MAX_TSAP_SEL_LEN
) || (val_len
<= 0)) {
570 printf("val_len 0x%x (*mp)->m_len %p\n",
574 memcpy((void *) tpcb
->tp_fsuffix
, value
, val_len
);
575 tpcb
->tp_fsuffixlen
= val_len
;
582 if (argo_debug
[D_REQUEST
]) {
583 printf("%s TPOPT_FLAGS value %p *value 0x%x, flags 0x%x \n",
584 cmd
== PRCO_GETOPT
? "GET" : "SET",
586 *(unsigned char *)value
,
591 if (cmd
== PRCO_GETOPT
) {
592 *(int *) value
= (int) tpcb
->tp_flags
;
593 (*mp
)->m_len
= sizeof(u_int
);
594 } else { /* cmd == PRCO_SETOPT */
602 * This handles: timer values, class, use of transport
603 * expedited data, max tpdu size, checksum, xtd format and
604 * disconnect indications, and may get rid of connect/disc
608 if (argo_debug
[D_SETPARAMS
]) {
609 printf("TPOPT_PARAMS value %p, cmd %s \n", value
,
610 cmd
== PRCO_GETOPT
? "GET" : "SET");
614 if (argo_debug
[D_REQUEST
]) {
615 printf("TPOPT_PARAMS value %p, cmd %s \n", value
,
616 cmd
== PRCO_GETOPT
? "GET" : "SET");
620 if (cmd
== PRCO_GETOPT
) {
621 *(struct tp_conn_param
*) value
= tpcb
->_tp_param
;
622 (*mp
)->m_len
= sizeof(tpcb
->_tp_param
);
623 } else { /* cmd == PRCO_SETOPT */
625 tp_consistency(tpcb
, TP_STRICT
| TP_FORCE
,
626 (struct tp_conn_param
*) value
)) == 0) {
628 * tp_consistency doesn't copy the whole set
631 tpcb
->_tp_param
= *(struct tp_conn_param
*) value
;
632 (*mp
)->m_len
= sizeof(tpcb
->_tp_param
);
637 case TPOPT_PSTATISTICS
:
639 if (cmd
== PRCO_SETOPT
) {
643 if (tpcb
->tp_perf_on
) {
644 m_clget(*mp
, M_WAIT
);
645 if (((*mp
)->m_flags
& M_EXT
) == 0) {
646 error
= ENOBUFS
; goto done
;
648 (*mp
)->m_len
= sizeof(struct tp_pmeas
);
649 memcpy(mtod(*mp
), tpcb
->tp_p_meas
, sizeof(struct tp_pmeas
));
659 #endif /* TP_PERF_MEAS */
661 case TPOPT_CDDATA_CLEAR
:
662 if (cmd
== PRCO_GETOPT
) {
665 if (tpcb
->tp_ucddata
) {
666 m_freem(tpcb
->tp_ucddata
);
667 tpcb
->tp_ucddata
= 0;
672 case TPOPT_CFRM_DATA
:
673 case TPOPT_DISC_DATA
:
674 case TPOPT_CONN_DATA
:
675 if (tpcb
->tp_class
== TP_CLASS_0
) {
680 if (argo_debug
[D_REQUEST
]) {
681 printf("%s\n", optname
== TPOPT_DISC_DATA
? "DISC data" : "CONN data");
682 printf("m_len 0x%x, vallen 0x%x so_snd.cc 0x%lx\n",
683 (*mp
)->m_len
, val_len
, so
->so_snd
.sb_cc
);
684 dump_mbuf(so
->so_snd
.sb_mb
, "tp_ctloutput: sosnd ");
687 if (cmd
== PRCO_SETOPT
) {
688 int len
= tpcb
->tp_ucddata
? tpcb
->tp_ucddata
->m_len
: 0;
689 /* can append connect data in several calls */
691 (optname
== TPOPT_CONN_DATA
? TP_MAX_CR_DATA
: TP_MAX_DR_DATA
)) {
695 (*mp
)->m_next
= NULL
;
696 (*mp
)->m_nextpkt
= 0;
697 if (tpcb
->tp_ucddata
)
698 m_cat(tpcb
->tp_ucddata
, *mp
);
700 tpcb
->tp_ucddata
= *mp
;
702 if (argo_debug
[D_REQUEST
]) {
703 dump_mbuf(tpcb
->tp_ucddata
, "tp_ctloutput after CONN_DATA");
707 if (tp_traceflags
[D_REQUEST
]) {
708 tptrace(TPPTmisc
, "C/D DATA: flags snd.sbcc val_len",
709 tpcb
->tp_flags
, so
->so_snd
.sb_cc
, val_len
, 0);
713 if (optname
== TPOPT_CFRM_DATA
&& (so
->so_state
& SS_ISCONFIRMING
))
714 (void) tp_confirm(tpcb
);
718 case TPOPT_PERF_MEAS
:
720 if (cmd
== PRCO_GETOPT
) {
721 *value
= (u_int
) tpcb
->tp_perf_on
;
722 (*mp
)->m_len
= sizeof(u_int
);
723 } else if (cmd
== PRCO_SETOPT
) {
725 if ((*value
) != 0 && (*value
) != 1)
728 tpcb
->tp_perf_on
= (*value
);
730 if (tpcb
->tp_perf_on
)
731 error
= tp_setup_perf(tpcb
);
732 #else /* TP_PERF_MEAS */
734 #endif /* TP_PERF_MEAS */
743 if (argo_debug
[D_REQUEST
]) {
744 dump_mbuf(so
->so_snd
.sb_mb
, "tp_ctloutput sosnd at end");
745 dump_mbuf(*mp
, "tp_ctloutput *mp");
749 * sigh: getsockopt looks only at m_len : all output data must reside
753 if (cmd
== PRCO_SETOPT
) {
757 ASSERT(m_compress(*mp
, mp
) <= MLEN
);
761 if (argo_debug
[D_REQUEST
]) {
762 dump_mbuf(*mp
, "tp_ctloutput *mp after compress");
772 * temporary sockopt wrapper, the above needs to be worked through
775 tp_ctloutput(int cmd
, struct socket
*so
, struct sockopt
*sopt
)
782 m
= sockopt_getmbuf(sopt
);
788 err
= tp_ctloutput1(cmd
, so
, sopt
->sopt_level
, sopt
->sopt_name
, &m
);
793 err
= tp_ctloutput1(cmd
, so
, sopt
->sopt_level
, sopt
->sopt_name
, &m
);
797 err
= sockopt_setmbuf(sopt
, m
);