136406Ssklower /*********************************************************** 236406Ssklower Copyright IBM Corporation 1987 336406Ssklower 436406Ssklower All Rights Reserved 536406Ssklower 636406Ssklower Permission to use, copy, modify, and distribute this software and its 736406Ssklower documentation for any purpose and without fee is hereby granted, 836406Ssklower provided that the above copyright notice appear in all copies and that 936406Ssklower both that copyright notice and this permission notice appear in 1036406Ssklower supporting documentation, and that the name of IBM not be 1136406Ssklower used in advertising or publicity pertaining to distribution of the 1236406Ssklower software without specific, written prior permission. 1336406Ssklower 1436406Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 1536406Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 1636406Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 1736406Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 1836406Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 1936406Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2036406Ssklower SOFTWARE. 2136406Ssklower 2236406Ssklower ******************************************************************/ 2336406Ssklower 2436406Ssklower /* 2536406Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 2636406Ssklower */ 2736406Ssklower /* 2836406Ssklower * ARGO TP 2936406Ssklower * 3036406Ssklower * $Header: tp_output.c,v 5.4 88/11/18 17:28:08 nhall Exp $ 3136406Ssklower * $Source: /usr/argo/sys/netiso/RCS/tp_output.c,v $ 32*38841Ssklower * @(#)tp_output.c 7.4 (Berkeley) 08/29/89 * 3336406Ssklower * 3436406Ssklower * In here is tp_ctloutput(), the guy called by [sg]etsockopt(), 3536406Ssklower */ 3636406Ssklower 3736406Ssklower #ifndef lint 3836406Ssklower static char *rcsid = "$Header: tp_output.c,v 5.4 88/11/18 17:28:08 nhall Exp $"; 3936406Ssklower #endif lint 4036406Ssklower 4136406Ssklower #include "param.h" 4236406Ssklower #include "systm.h" 4336406Ssklower #include "mbuf.h" 4436406Ssklower #include "protosw.h" 4536406Ssklower #include "socket.h" 4636406Ssklower #include "socketvar.h" 4736406Ssklower #include "errno.h" 4836406Ssklower #include "types.h" 4936406Ssklower #include "time.h" 5037469Ssklower #include "tp_param.h" 5137469Ssklower #include "tp_user.h" 5237469Ssklower #include "tp_stat.h" 5337469Ssklower #include "tp_ip.h" 5437469Ssklower #include "tp_timer.h" 5537469Ssklower #include "argo_debug.h" 5637469Ssklower #include "tp_pcb.h" 5737469Ssklower #include "tp_trace.h" 5836406Ssklower 5936406Ssklower #define USERFLAGSMASK_G 0x0f00643b 6036406Ssklower #define USERFLAGSMASK_S 0x0f000432 6136406Ssklower #define TPDUSIZESHIFT 24 6236406Ssklower #define CLASSHIFT 16 6336406Ssklower 6436406Ssklower /* 6536406Ssklower * NAME: tp_consistency() 6636406Ssklower * 6736406Ssklower * CALLED FROM: 6836406Ssklower * tp_ctloutput(), tp_input() 6936406Ssklower * 7036406Ssklower * FUNCTION and ARGUMENTS: 7136406Ssklower * Checks the consistency of options and tpdusize with class, 7236406Ssklower * using the parameters passed in via (param). 7336406Ssklower * (cmd) may be TP_STRICT or TP_FORCE or both. 7436406Ssklower * Force means it will set all the values in (tpcb) to those in 7536406Ssklower * the input arguements iff no errors were encountered. 7636406Ssklower * Strict means that no inconsistency will be tolerated. If it's 7736406Ssklower * not used, checksum and tpdusize inconsistencies will be tolerated. 7836406Ssklower * The reason for this is that in some cases, when we're negotiating down 7936406Ssklower * from class 4, these options should be changed but should not 8036406Ssklower * cause negotiation to fail. 8136406Ssklower * 8236406Ssklower * RETURNS 8336406Ssklower * E* or EOK 8436406Ssklower * E* if the various parms aren't ok for a given class 8536406Ssklower * EOK if they are ok for a given class 8636406Ssklower */ 8736406Ssklower 8836406Ssklower int 8936406Ssklower tp_consistency( tpcb, cmd, param ) 9036406Ssklower u_int cmd; 9136406Ssklower struct tp_conn_param *param; 9236406Ssklower struct tp_pcb *tpcb; 9336406Ssklower { 9436406Ssklower register int error = EOK; 9536406Ssklower int class_to_use = tp_mask_to_num(param->p_class); 9636406Ssklower 9736406Ssklower IFTRACE(D_SETPARAMS) 9836406Ssklower tptrace(TPPTmisc, 9936406Ssklower "tp_consist enter class_to_use dontchange param.class cmd", 10036406Ssklower class_to_use, param->p_dont_change_params, param->p_class, cmd); 10136406Ssklower ENDTRACE 10236406Ssklower IFDEBUG(D_SETPARAMS) 10336406Ssklower printf("tp_consistency %s %s\n", 10436406Ssklower cmd& TP_FORCE? "TP_FORCE": "", 10536406Ssklower cmd& TP_STRICT? "TP_STRICT":""); 10636406Ssklower ENDDEBUG 10736406Ssklower if ((cmd & TP_FORCE) && (param->p_dont_change_params)) { 10836406Ssklower cmd &= ~TP_FORCE; 10936406Ssklower } 11036406Ssklower /* can switch net services within a domain, but 11136406Ssklower * cannot switch domains 11236406Ssklower */ 11336406Ssklower switch( param->p_netservice) { 11436406Ssklower case ISO_CONS: 11536406Ssklower case ISO_CLNS: 11636406Ssklower case ISO_COSNS: 11736406Ssklower /* param->p_netservice in ISO DOMAIN */ 11836406Ssklower if(tpcb->tp_domain != AF_ISO ) { 11936406Ssklower error = EINVAL; goto done; 12036406Ssklower } 12136406Ssklower break; 12236406Ssklower case IN_CLNS: 12336406Ssklower /* param->p_netservice in INET DOMAIN */ 12436406Ssklower if( tpcb->tp_domain != AF_INET ) { 12536406Ssklower error = EINVAL; goto done; 12636406Ssklower } 12736406Ssklower break; 12836406Ssklower /* no others not possible-> netservice is a 2-bit field! */ 12936406Ssklower } 13036406Ssklower 13136406Ssklower IFDEBUG(D_SETPARAMS) 13236406Ssklower printf("p_class 0x%x, class_to_use 0x%x\n", param->p_class, 13336406Ssklower class_to_use); 13436406Ssklower ENDDEBUG 13536406Ssklower if((param->p_netservice < 0) || (param->p_netservice > TP_MAX_NETSERVICES)){ 13636406Ssklower error = EINVAL; goto done; 13736406Ssklower } 13836406Ssklower if( (param->p_class & TP_CLASSES_IMPLEMENTED) == 0 ) { 13936406Ssklower error = EINVAL; goto done; 14036406Ssklower } 14136406Ssklower IFDEBUG(D_SETPARAMS) 14236406Ssklower printf("Nretrans 0x%x\n", param->p_Nretrans ); 14336406Ssklower ENDDEBUG 14436406Ssklower if( ( param->p_Nretrans < 1 ) || 14536406Ssklower (param->p_cr_ticks < 1) || (param->p_cc_ticks < 1) ) { 14636406Ssklower /* bad for any class because negot has to be done a la class 4 */ 14736406Ssklower error = EINVAL; goto done; 14836406Ssklower } 14936406Ssklower IFDEBUG(D_SETPARAMS) 15036406Ssklower printf("winsize 0x%x\n", param->p_winsize ); 15136406Ssklower ENDDEBUG 15236406Ssklower if( (param->p_winsize < 128 ) || 15336406Ssklower (param->p_winsize < param->p_tpdusize ) || 15436406Ssklower (param->p_winsize > ((1+SB_MAX)>>2 /* 1/4 of the max */)) ) { 15536406Ssklower error = EINVAL; goto done; 15636406Ssklower } else { 15736406Ssklower if( tpcb->tp_state == TP_CLOSED ) 15837469Ssklower soreserve(tpcb->tp_sock, (u_long)param->p_winsize, 15937469Ssklower (u_long)param->p_winsize); 16036406Ssklower } 16136406Ssklower IFDEBUG(D_SETPARAMS) 16236406Ssklower printf("use_csum 0x%x\n", param->p_use_checksum ); 16336406Ssklower printf("xtd_format 0x%x\n", param->p_xtd_format ); 16436406Ssklower printf("xpd_service 0x%x\n", param->p_xpd_service ); 16536406Ssklower printf("tpdusize 0x%x\n", param->p_tpdusize ); 16636406Ssklower printf("tpcb->flags 0x%x\n", tpcb->tp_flags ); 16736406Ssklower ENDDEBUG 16836406Ssklower switch( class_to_use ) { 16936406Ssklower 17036406Ssklower case 0: 17136406Ssklower /* do not use checksums, xtd format, or XPD */ 17236406Ssklower 17336406Ssklower if( param->p_use_checksum | param->p_xtd_format | param->p_xpd_service ) { 17436406Ssklower if(cmd & TP_STRICT) { 17536406Ssklower error = EINVAL; 17636406Ssklower } else { 17736406Ssklower param->p_use_checksum = 0; 17836406Ssklower param->p_xtd_format = 0; 17936406Ssklower param->p_xpd_service = 0; 18036406Ssklower } 18136406Ssklower break; 18236406Ssklower } 18336406Ssklower 18436406Ssklower if (param->p_tpdusize < TP_MIN_TPDUSIZE) { 18536406Ssklower if(cmd & TP_STRICT) { 18636406Ssklower error = EINVAL; 18736406Ssklower } else { 18836406Ssklower param->p_tpdusize = TP_MIN_TPDUSIZE; 18936406Ssklower } 19036406Ssklower break; 19136406Ssklower } 19236406Ssklower if (param->p_tpdusize > TP0_TPDUSIZE) { 19336406Ssklower if (cmd & TP_STRICT) { 19436406Ssklower error = EINVAL; 19536406Ssklower } else { 19636406Ssklower param->p_tpdusize = TP0_TPDUSIZE; 19736406Ssklower } 19836406Ssklower break; 19936406Ssklower } 20036406Ssklower 20136406Ssklower /* connect/disc data not allowed for class 0 */ 20237469Ssklower if (tpcb->tp_ucddata) { 20336406Ssklower if(cmd & TP_STRICT) { 20436406Ssklower error = EINVAL; 20536406Ssklower } else if(cmd & TP_FORCE) { 20637469Ssklower m_freem(tpcb->tp_ucddata); 20737469Ssklower tpcb->tp_ucddata = 0; 20836406Ssklower } 20936406Ssklower } 21036406Ssklower break; 21136406Ssklower 21236406Ssklower case 4: 21336406Ssklower IFDEBUG(D_SETPARAMS) 21436406Ssklower printf("dt_ticks 0x%x\n", param->p_dt_ticks ); 21536406Ssklower printf("x_ticks 0x%x\n", param->p_x_ticks ); 21636406Ssklower printf("dr_ticks 0x%x\n", param->p_dr_ticks ); 21736406Ssklower printf("keepalive 0x%x\n", param->p_keepalive_ticks ); 21836406Ssklower printf("sendack 0x%x\n", param->p_sendack_ticks ); 21936406Ssklower printf("inact 0x%x\n", param->p_inact_ticks ); 22036406Ssklower printf("ref 0x%x\n", param->p_ref_ticks ); 22136406Ssklower ENDDEBUG 22236406Ssklower if( (param->p_class & TP_CLASS_4 ) && ( 22336406Ssklower (param->p_dt_ticks < 1) || (param->p_dr_ticks < 1) || 22436406Ssklower (param->p_x_ticks < 1) || (param->p_keepalive_ticks < 1) || 22536406Ssklower (param->p_sendack_ticks < 1) || (param->p_ref_ticks < 1) || 22636406Ssklower (param->p_inact_ticks < 1) ) ) { 22736406Ssklower error = EINVAL; 22836406Ssklower break; 22936406Ssklower } 23036406Ssklower IFDEBUG(D_SETPARAMS) 23136406Ssklower printf("rx_strat 0x%x\n", param->p_rx_strat ); 23236406Ssklower ENDDEBUG 23336406Ssklower if(param->p_rx_strat > 23436406Ssklower ( TPRX_USE_CW | TPRX_EACH | TPRX_FASTSTART) ) { 23536406Ssklower if(cmd & TP_STRICT) { 23636406Ssklower error = EINVAL; 23736406Ssklower } else { 23836406Ssklower param->p_rx_strat = TPRX_USE_CW; 23936406Ssklower } 24036406Ssklower break; 24136406Ssklower } 24236406Ssklower IFDEBUG(D_SETPARAMS) 24336406Ssklower printf("ack_strat 0x%x\n", param->p_ack_strat ); 24436406Ssklower ENDDEBUG 24536406Ssklower if((param->p_ack_strat != 0) && (param->p_ack_strat != 1)) { 24636406Ssklower if(cmd & TP_STRICT) { 24736406Ssklower error = EINVAL; 24836406Ssklower } else { 24936406Ssklower param->p_ack_strat = TPACK_WINDOW; 25036406Ssklower } 25136406Ssklower break; 25236406Ssklower } 25336406Ssklower if (param->p_tpdusize < TP_MIN_TPDUSIZE) { 25436406Ssklower if(cmd & TP_STRICT) { 25536406Ssklower error = EINVAL; 25636406Ssklower } else { 25736406Ssklower param->p_tpdusize = TP_MIN_TPDUSIZE; 25836406Ssklower } 25936406Ssklower break; 26036406Ssklower } 26136406Ssklower if (param->p_tpdusize > TP_TPDUSIZE) { 26236406Ssklower if(cmd & TP_STRICT) { 26336406Ssklower error = EINVAL; 26436406Ssklower } else { 26536406Ssklower param->p_tpdusize = TP_TPDUSIZE; 26636406Ssklower } 26736406Ssklower break; 26836406Ssklower } 26936406Ssklower break; 27036406Ssklower } 27136406Ssklower 27236406Ssklower if ((error==0) && (cmd & TP_FORCE)) { 27336406Ssklower tpcb->tp_tpdusize = param->p_tpdusize; 27436406Ssklower tpcb->tp_class = param->p_class; 27536406Ssklower tpcb->tp_use_checksum = param->p_use_checksum; 27636406Ssklower tpcb->tp_xpd_service = param->p_xpd_service; 27736406Ssklower tpcb->tp_xtd_format = param->p_xtd_format; 27836406Ssklower } 27936406Ssklower 28036406Ssklower done: 28136406Ssklower 28236406Ssklower IFTRACE(D_CONN) 28336406Ssklower tptrace(TPPTmisc, "tp_consist returns class xtdfmt cmd", 28436406Ssklower error, tpcb->tp_class, tpcb->tp_xtd_format, cmd); 28536406Ssklower ENDTRACE 28636406Ssklower IFDEBUG(D_CONN) 28736406Ssklower printf( 28836406Ssklower "tp_consist rtns 0x%x class 0x%x xtd_fmt 0x%x cmd 0x%x\n", 28936406Ssklower error, tpcb->tp_class, tpcb->tp_xtd_format, cmd); 29036406Ssklower ENDDEBUG 29136406Ssklower return error; 29236406Ssklower } 29336406Ssklower 29436406Ssklower /* 29536406Ssklower * NAME: tp_ctloutput() 29636406Ssklower * 29736406Ssklower * CALLED FROM: 29836406Ssklower * [sg]etsockopt(), via so[sg]etopt(). 29936406Ssklower * 30036406Ssklower * FUNCTION and ARGUMENTS: 30136406Ssklower * Implements the socket options at transport level. 30237536Smckusick * (cmd) is either PRCO_SETOPT or PRCO_GETOPT (see ../sys/protosw.h). 30336406Ssklower * (so) is the socket. 30437536Smckusick * (level) is SOL_TRANSPORT (see ../sys/socket.h) 30536406Ssklower * (optname) is the particular command or option to be set. 30636406Ssklower * (**mp) is an mbuf structure. 30736406Ssklower * 30836406Ssklower * RETURN VALUE: 30936406Ssklower * ENOTSOCK if the socket hasn't got an associated tpcb 31036406Ssklower * EINVAL if 31136406Ssklower * trying to set window too big 31236406Ssklower * trying to set illegal max tpdu size 31336406Ssklower * trying to set illegal credit fraction 31436406Ssklower * trying to use unknown or unimplemented class of TP 31536406Ssklower * structure passed to set timer values is wrong size 31636406Ssklower * illegal combination of command/GET-SET option, 31736406Ssklower * e.g., GET w/ TPOPT_CDDATA_CLEAR: 31836406Ssklower * EOPNOTSUPP if the level isn't transport, or command is neither GET nor SET 31936406Ssklower * or if the transport-specific command is not implemented 32036406Ssklower * EISCONN if trying a command that isn't allowed after a connection 32136406Ssklower * is established 32236406Ssklower * ENOTCONN if trying a command that is allowed only if a connection is 32336406Ssklower * established 32436406Ssklower * EMSGSIZE if trying to give too much data on connect/disconnect 32536406Ssklower * 32636406Ssklower * SIDE EFFECTS: 32736406Ssklower * 32836406Ssklower * NOTES: 32936406Ssklower */ 33036406Ssklower ProtoHook 33136406Ssklower tp_ctloutput(cmd, so, level, optname, mp) 33236406Ssklower int cmd, level, optname; 33336406Ssklower struct socket *so; 33436406Ssklower struct mbuf **mp; 33536406Ssklower { 33636406Ssklower struct tp_pcb *tpcb = sototpcb(so); 33736406Ssklower int s = splnet(); 33837469Ssklower caddr_t value; 33937469Ssklower unsigned val_len; 34036406Ssklower int error = 0; 34136406Ssklower 34236406Ssklower IFTRACE(D_REQUEST) 34336406Ssklower tptrace(TPPTmisc, "tp_ctloutput cmd so optname mp", 34436406Ssklower cmd, so, optname, mp); 34536406Ssklower ENDTRACE 34636406Ssklower IFDEBUG(D_REQUEST) 34736406Ssklower printf( 34836406Ssklower "tp_ctloutput so 0x%x cmd 0x%x optname 0x%x, mp 0x%x *mp 0x%x tpcb 0x%x\n", 34936406Ssklower so, cmd, optname, mp, mp?*mp:0, tpcb); 35036406Ssklower ENDDEBUG 35136406Ssklower if( tpcb == (struct tp_pcb *)0 ) { 35236406Ssklower error = ENOTSOCK; goto done; 35336406Ssklower } 35436406Ssklower if(*mp == MNULL) { 35536406Ssklower register struct mbuf *m; 35636406Ssklower 35736406Ssklower MGET(m, M_DONTWAIT, TPMT_SONAME); /* does off, type, next */ 35836406Ssklower if (m == NULL) { 35936406Ssklower splx(s); 36036406Ssklower return ENOBUFS; 36136406Ssklower } 36236406Ssklower m->m_len = 0; 36336406Ssklower m->m_act = 0; 36436406Ssklower *mp = m; 36536406Ssklower } 36636406Ssklower 36736406Ssklower /* 36836406Ssklower * Hook so one can set network options via a tp socket. 36936406Ssklower */ 37036406Ssklower if ( level == SOL_NETWORK ) { 37136406Ssklower if ((tpcb->tp_nlproto == NULL) || (tpcb->tp_npcb == NULL)) 37236406Ssklower error = ENOTSOCK; 37336406Ssklower else if (tpcb->tp_nlproto->nlp_ctloutput == NULL) 37436406Ssklower error = EOPNOTSUPP; 37536406Ssklower else 37636406Ssklower error = (tpcb->tp_nlproto->nlp_ctloutput)(cmd, optname, 37736406Ssklower tpcb->tp_npcb, *mp); 37836406Ssklower goto done; 37936406Ssklower } else if ( level != SOL_TRANSPORT ) { 38036406Ssklower error = EOPNOTSUPP; goto done; 38136406Ssklower } 38236406Ssklower if (cmd != PRCO_GETOPT && cmd != PRCO_SETOPT) { 38336406Ssklower error = EOPNOTSUPP; goto done; 38436406Ssklower } 38536406Ssklower if ( so->so_error ) { 38636406Ssklower error = so->so_error; goto done; 38736406Ssklower } 38836406Ssklower 38936406Ssklower /* The only options allowed after connection is established 39036406Ssklower * are GET (anything) and SET DISC DATA and SET PERF MEAS 39136406Ssklower */ 39236406Ssklower if ( ((so->so_state & SS_ISCONNECTING)||(so->so_state & SS_ISCONNECTED)) 39336406Ssklower && 39436406Ssklower (cmd == PRCO_SETOPT && 39536406Ssklower optname != TPOPT_DISC_DATA && 396*38841Ssklower optname != TPOPT_CFRM_DATA && 39736406Ssklower optname != TPOPT_PERF_MEAS && 39836406Ssklower optname != TPOPT_CDDATA_CLEAR ) ) { 39936406Ssklower error = EISCONN; goto done; 40036406Ssklower } 40136406Ssklower /* The only options allowed after disconnection are GET DISC DATA, 40236406Ssklower * and TPOPT_PSTATISTICS 40336406Ssklower * and they're not allowed if the ref timer has gone off, because 40436406Ssklower * the tpcb is gone 40536406Ssklower */ 406*38841Ssklower if ((so->so_state & (SS_ISCONNECTED | SS_ISCONFIRMING)) == 0) { 40736406Ssklower if ( so->so_tpcb == (caddr_t)0 ) { 40836406Ssklower error = ENOTCONN; goto done; 40936406Ssklower } 41036406Ssklower if ( (tpcb->tp_state == TP_REFWAIT || tpcb->tp_state == TP_CLOSING) && 41136406Ssklower (optname != TPOPT_DISC_DATA && optname != TPOPT_PSTATISTICS)) { 41236406Ssklower error = ENOTCONN; goto done; 41336406Ssklower } 41436406Ssklower } 41536406Ssklower 41637469Ssklower value = mtod(*mp, caddr_t); /* it's aligned, don't worry, 41737469Ssklower * but lint complains about it 41837469Ssklower */ 41936406Ssklower val_len = (*mp)->m_len; 42036406Ssklower 42136406Ssklower switch (optname) { 42236406Ssklower 42336406Ssklower case TPOPT_MY_TSEL: 42436406Ssklower if ( cmd == PRCO_GETOPT ) { 42536406Ssklower ASSERT( tpcb->tp_lsuffixlen <= MAX_TSAP_SEL_LEN ); 42637469Ssklower bcopy((caddr_t)tpcb->tp_lsuffix, value, tpcb->tp_lsuffixlen); 42736406Ssklower (*mp)->m_len = tpcb->tp_lsuffixlen; 42836406Ssklower } else /* cmd == PRCO_SETOPT */ { 42936406Ssklower if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { 43036406Ssklower printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); 43136406Ssklower error = EINVAL; 43236406Ssklower } else { 43337469Ssklower bcopy(value, (caddr_t)tpcb->tp_lsuffix, val_len); 43436406Ssklower tpcb->tp_lsuffixlen = val_len; 43536406Ssklower } 43636406Ssklower } 43736406Ssklower break; 43836406Ssklower 43936406Ssklower case TPOPT_PEER_TSEL: 44036406Ssklower if ( cmd == PRCO_GETOPT ) { 44136406Ssklower ASSERT( tpcb->tp_fsuffixlen <= MAX_TSAP_SEL_LEN ); 44237469Ssklower bcopy((caddr_t)tpcb->tp_fsuffix, value, tpcb->tp_fsuffixlen); 44336406Ssklower (*mp)->m_len = tpcb->tp_fsuffixlen; 44436406Ssklower } else /* cmd == PRCO_SETOPT */ { 44536406Ssklower if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { 44636406Ssklower printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); 44736406Ssklower error = EINVAL; 44836406Ssklower } else { 44937469Ssklower bcopy(value, (caddr_t)tpcb->tp_fsuffix, val_len); 45036406Ssklower tpcb->tp_fsuffixlen = val_len; 45136406Ssklower } 45236406Ssklower } 45336406Ssklower break; 45436406Ssklower 45536406Ssklower case TPOPT_FLAGS: 45636406Ssklower IFDEBUG(D_REQUEST) 45736406Ssklower printf("%s TPOPT_FLAGS value 0x%x *value 0x%x, flags 0x%x \n", 45836406Ssklower cmd==PRCO_GETOPT?"GET":"SET", 45936406Ssklower value, 46036406Ssklower *value, 46136406Ssklower tpcb->tp_flags); 46236406Ssklower ENDDEBUG 46336406Ssklower 46436406Ssklower if ( cmd == PRCO_GETOPT ) { 46536406Ssklower *(int *)value = (int)tpcb->tp_flags; 46636406Ssklower (*mp)->m_len = sizeof(u_int); 46736406Ssklower } else /* cmd == PRCO_SETOPT */ { 46836406Ssklower error = EINVAL; goto done; 46936406Ssklower } 47036406Ssklower break; 47136406Ssklower 47236406Ssklower case TPOPT_PARAMS: 47336406Ssklower /* This handles: 47436406Ssklower * timer values, 47536406Ssklower * class, use of transport expedited data, 47636406Ssklower * max tpdu size, checksum, xtd format and 47736406Ssklower * disconnect indications, and may get rid of connect/disc data 47836406Ssklower */ 47936406Ssklower IFDEBUG(D_SETPARAMS) 48036406Ssklower printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, 48136406Ssklower cmd==PRCO_GETOPT?"GET":"SET"); 48236406Ssklower ENDDEBUG 48336406Ssklower IFDEBUG(D_REQUEST) 48436406Ssklower printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, 48536406Ssklower cmd==PRCO_GETOPT?"GET":"SET"); 48636406Ssklower ENDDEBUG 48736406Ssklower 48836406Ssklower if ( cmd == PRCO_GETOPT ) { 48936406Ssklower *(struct tp_conn_param *)value = tpcb->_tp_param; 49036406Ssklower (*mp)->m_len = sizeof(tpcb->_tp_param); 49136406Ssklower } else /* cmd == PRCO_SETOPT */ { 49236406Ssklower if( (error = 49336406Ssklower tp_consistency(tpcb, TP_STRICT | TP_FORCE, 49436406Ssklower (struct tp_conn_param *)value))==0) { 49536406Ssklower /* 49636406Ssklower * tp_consistency doesn't copy the whole set of params 49736406Ssklower */ 49836406Ssklower tpcb->_tp_param = *(struct tp_conn_param *)value; 49936406Ssklower (*mp)->m_len = sizeof(tpcb->_tp_param); 50036406Ssklower } 50136406Ssklower } 50236406Ssklower break; 50336406Ssklower 50436406Ssklower case TPOPT_PSTATISTICS: 50536406Ssklower #ifdef TP_PERF_MEAS 50636406Ssklower if (cmd == PRCO_SETOPT) { 50736406Ssklower error = EINVAL; goto done; 50836406Ssklower } 50936406Ssklower IFPERF(tpcb) 51037469Ssklower if (*mp) { 51137469Ssklower struct mbuf * n; 51237469Ssklower do { 51337469Ssklower MFREE(*mp, n); 51437469Ssklower *mp = n; 51537469Ssklower } while (n); 51637469Ssklower } 51737469Ssklower *mp = m_copym(tpcb->tp_p_mbuf, (int)M_COPYALL, M_WAITOK); 51836406Ssklower ENDPERF 51936406Ssklower else { 52036406Ssklower error = EINVAL; goto done; 52136406Ssklower } 52236406Ssklower break; 52336406Ssklower #else 52436406Ssklower error = EOPNOTSUPP; 52536406Ssklower goto done; 52636406Ssklower #endif TP_PERF_MEAS 52736406Ssklower 52836406Ssklower case TPOPT_CDDATA_CLEAR: 52936406Ssklower if (cmd == PRCO_GETOPT) { 53036406Ssklower error = EINVAL; 53136406Ssklower } else { 53237469Ssklower if (tpcb->tp_ucddata) { 533*38841Ssklower m_freem(tpcb->tp_ucddata); 534*38841Ssklower tpcb->tp_ucddata = 0; 53536406Ssklower } 53636406Ssklower } 53736406Ssklower break; 53836406Ssklower 539*38841Ssklower #ifdef TPOPT_NGC8_ACCEPT 540*38841Ssklower case TPOPT_NGC8_ACCEPT: 541*38841Ssklower if ( cmd == PRCO_GETOPT ) { 542*38841Ssklower *(int *)value = (int)tpcb->tp_flags & TPFLAG_NGC8_ACCEPT; 543*38841Ssklower (*mp)->m_len = sizeof(u_int); 544*38841Ssklower } else { 545*38841Ssklower if (*(int *)value) 546*38841Ssklower tpcb->tp_flags |= TPFLAG_NGC8_ACCEPT; 547*38841Ssklower else 548*38841Ssklower tpcb->tp_flags &= ~TPFLAG_NGC8_ACCEPT; 549*38841Ssklower } 550*38841Ssklower break; 551*38841Ssklower #endif 552*38841Ssklower 553*38841Ssklower case TPOPT_CFRM_DATA: 554*38841Ssklower if (cmd == PRCO_SETOPT && (so->so_state & SS_ISCONFIRMING)) 555*38841Ssklower (void) tp_confirm(tpcb); 556*38841Ssklower /* drop through */ 55736406Ssklower case TPOPT_DISC_DATA: 55836406Ssklower /* drop through */ 55936406Ssklower /* sending is for debugging purposes only -- we don't pretend 56036406Ssklower * to support * data on connect or disconnect fully. It's a 56136406Ssklower * kludge at best. 56236406Ssklower * This data-on-connect is only for the active side. It's sort of 56336406Ssklower * meaningless on the passive side (because 56436406Ssklower * you can't reject a connect request based on the data 56536406Ssklower * arriving w/ the CR, this, and because you'd have to 56636406Ssklower * do this setsockopt system call for each accept). 56736406Ssklower * but you can use it if you want. 56836406Ssklower */ 56936406Ssklower case TPOPT_CONN_DATA: 57036406Ssklower if( tpcb->tp_class == TP_CLASS_0 ) { 57136406Ssklower error = EOPNOTSUPP; 57236406Ssklower break; 57336406Ssklower } 57436406Ssklower IFDEBUG(D_REQUEST) 57536406Ssklower printf("%s\n", optname==TPOPT_DISC_DATA?"DISC data":"CONN data"); 57636406Ssklower printf("m_len 0x%x, vallen 0x%x so_snd.cc 0x%x\n", 57736406Ssklower (*mp)->m_len, val_len, so->so_snd.sb_cc); 57836406Ssklower dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput: sosnd "); 57936406Ssklower ENDDEBUG 58036406Ssklower if (cmd == PRCO_SETOPT) { 58137469Ssklower int len = tpcb->tp_ucddata ? tpcb->tp_ucddata->m_len : 0; 58236406Ssklower /* can append connect data in several calls */ 58337469Ssklower if (len + val_len > 58436406Ssklower (optname==TPOPT_CONN_DATA?TP_MAX_CR_DATA:TP_MAX_DR_DATA) ) { 58536406Ssklower error = EMSGSIZE; goto done; 58636406Ssklower } 58736406Ssklower (*mp)->m_next = MNULL; 58836406Ssklower (*mp)->m_act = 0; 58937469Ssklower if (tpcb->tp_ucddata) 59037469Ssklower m_cat(tpcb->tp_ucddata, *mp); 59137469Ssklower else 59237469Ssklower tpcb->tp_ucddata = *mp; 59336406Ssklower IFDEBUG(D_REQUEST) 59437469Ssklower dump_mbuf(tpcb->tp_ucddata, "tp_ctloutput after CONN_DATA"); 59536406Ssklower ENDDEBUG 59636406Ssklower IFTRACE(D_REQUEST) 59736406Ssklower tptrace(TPPTmisc,"C/D DATA: flags snd.sbcc val_len", 59836406Ssklower tpcb->tp_flags, so->so_snd.sb_cc,val_len,0); 59936406Ssklower ENDTRACE 60036406Ssklower *mp = MNULL; /* prevent sosetopt from freeing it! */ 60136406Ssklower } 60236406Ssklower break; 60336406Ssklower 60436406Ssklower case TPOPT_PERF_MEAS: 60536406Ssklower #ifdef TP_PERF_MEAS 60636406Ssklower if (cmd == PRCO_GETOPT) { 60736406Ssklower *value = (u_int)tpcb->tp_perf_on; 60836406Ssklower (*mp)->m_len = sizeof(u_int); 60936406Ssklower } else if (cmd == PRCO_SETOPT) { 61036406Ssklower (*mp)->m_len = 0; 61136406Ssklower if ((*value) != 0 && (*value) != 1 ) 61236406Ssklower error = EINVAL; 61336406Ssklower else tpcb->tp_perf_on = (*value); 61436406Ssklower } 61536406Ssklower if( tpcb->tp_perf_on ) 61636406Ssklower error = tp_setup_perf(tpcb); 61736406Ssklower #else TP_PERF_MEAS 61836406Ssklower error = EOPNOTSUPP; 61936406Ssklower #endif TP_PERF_MEAS 62036406Ssklower break; 62136406Ssklower 62236406Ssklower default: 62336406Ssklower error = EOPNOTSUPP; 62436406Ssklower } 62536406Ssklower 62636406Ssklower done: 62736406Ssklower IFDEBUG(D_REQUEST) 62836406Ssklower dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput sosnd at end"); 62936406Ssklower dump_mbuf(*mp, "tp_ctloutput *mp"); 63036406Ssklower ENDDEBUG 63136406Ssklower /* 63236406Ssklower * sigh: getsockopt looks only at m_len : all output data must 63336406Ssklower * reside in the first mbuf 63436406Ssklower */ 63536406Ssklower if ( error && (*mp) != MNULL ) 63636406Ssklower (*mp)->m_len = 0; 63736406Ssklower if( (*mp) != MNULL ) { 63836406Ssklower ASSERT ( m_compress(*mp, mp) <= MLEN ); 63936406Ssklower IFDEBUG(D_REQUEST) 64036406Ssklower dump_mbuf(*mp, "tp_ctloutput *mp after compress"); 64136406Ssklower ENDDEBUG 64236406Ssklower } 64336406Ssklower 64436406Ssklower splx(s); 64536406Ssklower return error; 64636406Ssklower } 647