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 $ 3236406Ssklower * 3336406Ssklower * In here is tp_ctloutput(), the guy called by [sg]etsockopt(), 3436406Ssklower */ 3536406Ssklower 3636406Ssklower #ifndef lint 3736406Ssklower static char *rcsid = "$Header: tp_output.c,v 5.4 88/11/18 17:28:08 nhall Exp $"; 3836406Ssklower #endif lint 3936406Ssklower 4036406Ssklower #include "param.h" 4136406Ssklower #include "systm.h" 4236406Ssklower #include "mbuf.h" 4336406Ssklower #include "protosw.h" 4436406Ssklower #include "socket.h" 4536406Ssklower #include "socketvar.h" 4636406Ssklower #include "errno.h" 4736406Ssklower #include "types.h" 4836406Ssklower #include "time.h" 49*37469Ssklower #include "tp_param.h" 50*37469Ssklower #include "tp_user.h" 51*37469Ssklower #include "tp_stat.h" 52*37469Ssklower #include "tp_ip.h" 53*37469Ssklower #include "tp_timer.h" 54*37469Ssklower #include "argo_debug.h" 55*37469Ssklower #include "tp_pcb.h" 56*37469Ssklower #include "tp_trace.h" 5736406Ssklower 5836406Ssklower #define USERFLAGSMASK_G 0x0f00643b 5936406Ssklower #define USERFLAGSMASK_S 0x0f000432 6036406Ssklower #define TPDUSIZESHIFT 24 6136406Ssklower #define CLASSHIFT 16 6236406Ssklower 6336406Ssklower /* 6436406Ssklower * NAME: tp_consistency() 6536406Ssklower * 6636406Ssklower * CALLED FROM: 6736406Ssklower * tp_ctloutput(), tp_input() 6836406Ssklower * 6936406Ssklower * FUNCTION and ARGUMENTS: 7036406Ssklower * Checks the consistency of options and tpdusize with class, 7136406Ssklower * using the parameters passed in via (param). 7236406Ssklower * (cmd) may be TP_STRICT or TP_FORCE or both. 7336406Ssklower * Force means it will set all the values in (tpcb) to those in 7436406Ssklower * the input arguements iff no errors were encountered. 7536406Ssklower * Strict means that no inconsistency will be tolerated. If it's 7636406Ssklower * not used, checksum and tpdusize inconsistencies will be tolerated. 7736406Ssklower * The reason for this is that in some cases, when we're negotiating down 7836406Ssklower * from class 4, these options should be changed but should not 7936406Ssklower * cause negotiation to fail. 8036406Ssklower * 8136406Ssklower * RETURNS 8236406Ssklower * E* or EOK 8336406Ssklower * E* if the various parms aren't ok for a given class 8436406Ssklower * EOK if they are ok for a given class 8536406Ssklower */ 8636406Ssklower 8736406Ssklower int 8836406Ssklower tp_consistency( tpcb, cmd, param ) 8936406Ssklower u_int cmd; 9036406Ssklower struct tp_conn_param *param; 9136406Ssklower struct tp_pcb *tpcb; 9236406Ssklower { 9336406Ssklower register int error = EOK; 9436406Ssklower int class_to_use = tp_mask_to_num(param->p_class); 9536406Ssklower 9636406Ssklower IFTRACE(D_SETPARAMS) 9736406Ssklower tptrace(TPPTmisc, 9836406Ssklower "tp_consist enter class_to_use dontchange param.class cmd", 9936406Ssklower class_to_use, param->p_dont_change_params, param->p_class, cmd); 10036406Ssklower ENDTRACE 10136406Ssklower IFDEBUG(D_SETPARAMS) 10236406Ssklower printf("tp_consistency %s %s\n", 10336406Ssklower cmd& TP_FORCE? "TP_FORCE": "", 10436406Ssklower cmd& TP_STRICT? "TP_STRICT":""); 10536406Ssklower ENDDEBUG 10636406Ssklower if ((cmd & TP_FORCE) && (param->p_dont_change_params)) { 10736406Ssklower cmd &= ~TP_FORCE; 10836406Ssklower } 10936406Ssklower /* can switch net services within a domain, but 11036406Ssklower * cannot switch domains 11136406Ssklower */ 11236406Ssklower switch( param->p_netservice) { 11336406Ssklower case ISO_CONS: 11436406Ssklower case ISO_CLNS: 11536406Ssklower case ISO_COSNS: 11636406Ssklower /* param->p_netservice in ISO DOMAIN */ 11736406Ssklower if(tpcb->tp_domain != AF_ISO ) { 11836406Ssklower error = EINVAL; goto done; 11936406Ssklower } 12036406Ssklower break; 12136406Ssklower case IN_CLNS: 12236406Ssklower /* param->p_netservice in INET DOMAIN */ 12336406Ssklower if( tpcb->tp_domain != AF_INET ) { 12436406Ssklower error = EINVAL; goto done; 12536406Ssklower } 12636406Ssklower break; 12736406Ssklower /* no others not possible-> netservice is a 2-bit field! */ 12836406Ssklower } 12936406Ssklower 13036406Ssklower IFDEBUG(D_SETPARAMS) 13136406Ssklower printf("p_class 0x%x, class_to_use 0x%x\n", param->p_class, 13236406Ssklower class_to_use); 13336406Ssklower ENDDEBUG 13436406Ssklower if((param->p_netservice < 0) || (param->p_netservice > TP_MAX_NETSERVICES)){ 13536406Ssklower error = EINVAL; goto done; 13636406Ssklower } 13736406Ssklower if( (param->p_class & TP_CLASSES_IMPLEMENTED) == 0 ) { 13836406Ssklower error = EINVAL; goto done; 13936406Ssklower } 14036406Ssklower IFDEBUG(D_SETPARAMS) 14136406Ssklower printf("Nretrans 0x%x\n", param->p_Nretrans ); 14236406Ssklower ENDDEBUG 14336406Ssklower if( ( param->p_Nretrans < 1 ) || 14436406Ssklower (param->p_cr_ticks < 1) || (param->p_cc_ticks < 1) ) { 14536406Ssklower /* bad for any class because negot has to be done a la class 4 */ 14636406Ssklower error = EINVAL; goto done; 14736406Ssklower } 14836406Ssklower IFDEBUG(D_SETPARAMS) 14936406Ssklower printf("winsize 0x%x\n", param->p_winsize ); 15036406Ssklower ENDDEBUG 15136406Ssklower if( (param->p_winsize < 128 ) || 15236406Ssklower (param->p_winsize < param->p_tpdusize ) || 15336406Ssklower (param->p_winsize > ((1+SB_MAX)>>2 /* 1/4 of the max */)) ) { 15436406Ssklower error = EINVAL; goto done; 15536406Ssklower } else { 15636406Ssklower if( tpcb->tp_state == TP_CLOSED ) 157*37469Ssklower soreserve(tpcb->tp_sock, (u_long)param->p_winsize, 158*37469Ssklower (u_long)param->p_winsize); 15936406Ssklower } 16036406Ssklower IFDEBUG(D_SETPARAMS) 16136406Ssklower printf("use_csum 0x%x\n", param->p_use_checksum ); 16236406Ssklower printf("xtd_format 0x%x\n", param->p_xtd_format ); 16336406Ssklower printf("xpd_service 0x%x\n", param->p_xpd_service ); 16436406Ssklower printf("tpdusize 0x%x\n", param->p_tpdusize ); 16536406Ssklower printf("tpcb->flags 0x%x\n", tpcb->tp_flags ); 16636406Ssklower ENDDEBUG 16736406Ssklower switch( class_to_use ) { 16836406Ssklower 16936406Ssklower case 0: 17036406Ssklower /* do not use checksums, xtd format, or XPD */ 17136406Ssklower 17236406Ssklower if( param->p_use_checksum | param->p_xtd_format | param->p_xpd_service ) { 17336406Ssklower if(cmd & TP_STRICT) { 17436406Ssklower error = EINVAL; 17536406Ssklower } else { 17636406Ssklower param->p_use_checksum = 0; 17736406Ssklower param->p_xtd_format = 0; 17836406Ssklower param->p_xpd_service = 0; 17936406Ssklower } 18036406Ssklower break; 18136406Ssklower } 18236406Ssklower 18336406Ssklower if (param->p_tpdusize < TP_MIN_TPDUSIZE) { 18436406Ssklower if(cmd & TP_STRICT) { 18536406Ssklower error = EINVAL; 18636406Ssklower } else { 18736406Ssklower param->p_tpdusize = TP_MIN_TPDUSIZE; 18836406Ssklower } 18936406Ssklower break; 19036406Ssklower } 19136406Ssklower if (param->p_tpdusize > TP0_TPDUSIZE) { 19236406Ssklower if (cmd & TP_STRICT) { 19336406Ssklower error = EINVAL; 19436406Ssklower } else { 19536406Ssklower param->p_tpdusize = TP0_TPDUSIZE; 19636406Ssklower } 19736406Ssklower break; 19836406Ssklower } 19936406Ssklower 20036406Ssklower /* connect/disc data not allowed for class 0 */ 201*37469Ssklower if (tpcb->tp_ucddata) { 20236406Ssklower if(cmd & TP_STRICT) { 20336406Ssklower error = EINVAL; 20436406Ssklower } else if(cmd & TP_FORCE) { 205*37469Ssklower m_freem(tpcb->tp_ucddata); 206*37469Ssklower tpcb->tp_ucddata = 0; 20736406Ssklower } 20836406Ssklower } 20936406Ssklower break; 21036406Ssklower 21136406Ssklower case 4: 21236406Ssklower IFDEBUG(D_SETPARAMS) 21336406Ssklower printf("dt_ticks 0x%x\n", param->p_dt_ticks ); 21436406Ssklower printf("x_ticks 0x%x\n", param->p_x_ticks ); 21536406Ssklower printf("dr_ticks 0x%x\n", param->p_dr_ticks ); 21636406Ssklower printf("keepalive 0x%x\n", param->p_keepalive_ticks ); 21736406Ssklower printf("sendack 0x%x\n", param->p_sendack_ticks ); 21836406Ssklower printf("inact 0x%x\n", param->p_inact_ticks ); 21936406Ssklower printf("ref 0x%x\n", param->p_ref_ticks ); 22036406Ssklower ENDDEBUG 22136406Ssklower if( (param->p_class & TP_CLASS_4 ) && ( 22236406Ssklower (param->p_dt_ticks < 1) || (param->p_dr_ticks < 1) || 22336406Ssklower (param->p_x_ticks < 1) || (param->p_keepalive_ticks < 1) || 22436406Ssklower (param->p_sendack_ticks < 1) || (param->p_ref_ticks < 1) || 22536406Ssklower (param->p_inact_ticks < 1) ) ) { 22636406Ssklower error = EINVAL; 22736406Ssklower break; 22836406Ssklower } 22936406Ssklower IFDEBUG(D_SETPARAMS) 23036406Ssklower printf("rx_strat 0x%x\n", param->p_rx_strat ); 23136406Ssklower ENDDEBUG 23236406Ssklower if(param->p_rx_strat > 23336406Ssklower ( TPRX_USE_CW | TPRX_EACH | TPRX_FASTSTART) ) { 23436406Ssklower if(cmd & TP_STRICT) { 23536406Ssklower error = EINVAL; 23636406Ssklower } else { 23736406Ssklower param->p_rx_strat = TPRX_USE_CW; 23836406Ssklower } 23936406Ssklower break; 24036406Ssklower } 24136406Ssklower IFDEBUG(D_SETPARAMS) 24236406Ssklower printf("ack_strat 0x%x\n", param->p_ack_strat ); 24336406Ssklower ENDDEBUG 24436406Ssklower if((param->p_ack_strat != 0) && (param->p_ack_strat != 1)) { 24536406Ssklower if(cmd & TP_STRICT) { 24636406Ssklower error = EINVAL; 24736406Ssklower } else { 24836406Ssklower param->p_ack_strat = TPACK_WINDOW; 24936406Ssklower } 25036406Ssklower break; 25136406Ssklower } 25236406Ssklower if (param->p_tpdusize < TP_MIN_TPDUSIZE) { 25336406Ssklower if(cmd & TP_STRICT) { 25436406Ssklower error = EINVAL; 25536406Ssklower } else { 25636406Ssklower param->p_tpdusize = TP_MIN_TPDUSIZE; 25736406Ssklower } 25836406Ssklower break; 25936406Ssklower } 26036406Ssklower if (param->p_tpdusize > TP_TPDUSIZE) { 26136406Ssklower if(cmd & TP_STRICT) { 26236406Ssklower error = EINVAL; 26336406Ssklower } else { 26436406Ssklower param->p_tpdusize = TP_TPDUSIZE; 26536406Ssklower } 26636406Ssklower break; 26736406Ssklower } 26836406Ssklower break; 26936406Ssklower } 27036406Ssklower 27136406Ssklower if ((error==0) && (cmd & TP_FORCE)) { 27236406Ssklower tpcb->tp_tpdusize = param->p_tpdusize; 27336406Ssklower tpcb->tp_class = param->p_class; 27436406Ssklower tpcb->tp_use_checksum = param->p_use_checksum; 27536406Ssklower tpcb->tp_xpd_service = param->p_xpd_service; 27636406Ssklower tpcb->tp_xtd_format = param->p_xtd_format; 27736406Ssklower } 27836406Ssklower 27936406Ssklower done: 28036406Ssklower 28136406Ssklower IFTRACE(D_CONN) 28236406Ssklower tptrace(TPPTmisc, "tp_consist returns class xtdfmt cmd", 28336406Ssklower error, tpcb->tp_class, tpcb->tp_xtd_format, cmd); 28436406Ssklower ENDTRACE 28536406Ssklower IFDEBUG(D_CONN) 28636406Ssklower printf( 28736406Ssklower "tp_consist rtns 0x%x class 0x%x xtd_fmt 0x%x cmd 0x%x\n", 28836406Ssklower error, tpcb->tp_class, tpcb->tp_xtd_format, cmd); 28936406Ssklower ENDDEBUG 29036406Ssklower return error; 29136406Ssklower } 29236406Ssklower 29336406Ssklower /* 29436406Ssklower * NAME: tp_ctloutput() 29536406Ssklower * 29636406Ssklower * CALLED FROM: 29736406Ssklower * [sg]etsockopt(), via so[sg]etopt(). 29836406Ssklower * 29936406Ssklower * FUNCTION and ARGUMENTS: 30036406Ssklower * Implements the socket options at transport level. 30136406Ssklower * (cmd) is either PRCO_SETOPT or PRCO_GETOPT (see ../h/protosw.h). 30236406Ssklower * (so) is the socket. 30336406Ssklower * (level) is SOL_TRANSPORT (see ../h/socket.h) 30436406Ssklower * (optname) is the particular command or option to be set. 30536406Ssklower * (**mp) is an mbuf structure. 30636406Ssklower * 30736406Ssklower * RETURN VALUE: 30836406Ssklower * ENOTSOCK if the socket hasn't got an associated tpcb 30936406Ssklower * EINVAL if 31036406Ssklower * trying to set window too big 31136406Ssklower * trying to set illegal max tpdu size 31236406Ssklower * trying to set illegal credit fraction 31336406Ssklower * trying to use unknown or unimplemented class of TP 31436406Ssklower * structure passed to set timer values is wrong size 31536406Ssklower * illegal combination of command/GET-SET option, 31636406Ssklower * e.g., GET w/ TPOPT_CDDATA_CLEAR: 31736406Ssklower * EOPNOTSUPP if the level isn't transport, or command is neither GET nor SET 31836406Ssklower * or if the transport-specific command is not implemented 31936406Ssklower * EISCONN if trying a command that isn't allowed after a connection 32036406Ssklower * is established 32136406Ssklower * ENOTCONN if trying a command that is allowed only if a connection is 32236406Ssklower * established 32336406Ssklower * EMSGSIZE if trying to give too much data on connect/disconnect 32436406Ssklower * 32536406Ssklower * SIDE EFFECTS: 32636406Ssklower * 32736406Ssklower * NOTES: 32836406Ssklower */ 32936406Ssklower ProtoHook 33036406Ssklower tp_ctloutput(cmd, so, level, optname, mp) 33136406Ssklower int cmd, level, optname; 33236406Ssklower struct socket *so; 33336406Ssklower struct mbuf **mp; 33436406Ssklower { 33536406Ssklower struct tp_pcb *tpcb = sototpcb(so); 33636406Ssklower int s = splnet(); 337*37469Ssklower caddr_t value; 338*37469Ssklower unsigned val_len; 33936406Ssklower int error = 0; 34036406Ssklower 34136406Ssklower IFTRACE(D_REQUEST) 34236406Ssklower tptrace(TPPTmisc, "tp_ctloutput cmd so optname mp", 34336406Ssklower cmd, so, optname, mp); 34436406Ssklower ENDTRACE 34536406Ssklower IFDEBUG(D_REQUEST) 34636406Ssklower printf( 34736406Ssklower "tp_ctloutput so 0x%x cmd 0x%x optname 0x%x, mp 0x%x *mp 0x%x tpcb 0x%x\n", 34836406Ssklower so, cmd, optname, mp, mp?*mp:0, tpcb); 34936406Ssklower ENDDEBUG 35036406Ssklower if( tpcb == (struct tp_pcb *)0 ) { 35136406Ssklower error = ENOTSOCK; goto done; 35236406Ssklower } 35336406Ssklower if(*mp == MNULL) { 35436406Ssklower register struct mbuf *m; 35536406Ssklower 35636406Ssklower MGET(m, M_DONTWAIT, TPMT_SONAME); /* does off, type, next */ 35736406Ssklower if (m == NULL) { 35836406Ssklower splx(s); 35936406Ssklower return ENOBUFS; 36036406Ssklower } 36136406Ssklower m->m_len = 0; 36236406Ssklower m->m_act = 0; 36336406Ssklower *mp = m; 36436406Ssklower } 36536406Ssklower 36636406Ssklower /* 36736406Ssklower * Hook so one can set network options via a tp socket. 36836406Ssklower */ 36936406Ssklower if ( level == SOL_NETWORK ) { 37036406Ssklower if ((tpcb->tp_nlproto == NULL) || (tpcb->tp_npcb == NULL)) 37136406Ssklower error = ENOTSOCK; 37236406Ssklower else if (tpcb->tp_nlproto->nlp_ctloutput == NULL) 37336406Ssklower error = EOPNOTSUPP; 37436406Ssklower else 37536406Ssklower error = (tpcb->tp_nlproto->nlp_ctloutput)(cmd, optname, 37636406Ssklower tpcb->tp_npcb, *mp); 37736406Ssklower goto done; 37836406Ssklower } else if ( level != SOL_TRANSPORT ) { 37936406Ssklower error = EOPNOTSUPP; goto done; 38036406Ssklower } 38136406Ssklower if (cmd != PRCO_GETOPT && cmd != PRCO_SETOPT) { 38236406Ssklower error = EOPNOTSUPP; goto done; 38336406Ssklower } 38436406Ssklower if ( so->so_error ) { 38536406Ssklower error = so->so_error; goto done; 38636406Ssklower } 38736406Ssklower 38836406Ssklower /* The only options allowed after connection is established 38936406Ssklower * are GET (anything) and SET DISC DATA and SET PERF MEAS 39036406Ssklower */ 39136406Ssklower if ( ((so->so_state & SS_ISCONNECTING)||(so->so_state & SS_ISCONNECTED)) 39236406Ssklower && 39336406Ssklower (cmd == PRCO_SETOPT && 39436406Ssklower optname != TPOPT_DISC_DATA && 39536406Ssklower optname != TPOPT_PERF_MEAS && 39636406Ssklower optname != TPOPT_CDDATA_CLEAR ) ) { 39736406Ssklower error = EISCONN; goto done; 39836406Ssklower } 39936406Ssklower /* The only options allowed after disconnection are GET DISC DATA, 40036406Ssklower * and TPOPT_PSTATISTICS 40136406Ssklower * and they're not allowed if the ref timer has gone off, because 40236406Ssklower * the tpcb is gone 40336406Ssklower */ 40436406Ssklower if ((so->so_state & SS_ISCONNECTED) == 0) { 40536406Ssklower if ( so->so_tpcb == (caddr_t)0 ) { 40636406Ssklower error = ENOTCONN; goto done; 40736406Ssklower } 40836406Ssklower if ( (tpcb->tp_state == TP_REFWAIT || tpcb->tp_state == TP_CLOSING) && 40936406Ssklower (optname != TPOPT_DISC_DATA && optname != TPOPT_PSTATISTICS)) { 41036406Ssklower error = ENOTCONN; goto done; 41136406Ssklower } 41236406Ssklower } 41336406Ssklower 414*37469Ssklower value = mtod(*mp, caddr_t); /* it's aligned, don't worry, 415*37469Ssklower * but lint complains about it 416*37469Ssklower */ 41736406Ssklower val_len = (*mp)->m_len; 41836406Ssklower 41936406Ssklower switch (optname) { 42036406Ssklower 42136406Ssklower case TPOPT_MY_TSEL: 42236406Ssklower if ( cmd == PRCO_GETOPT ) { 42336406Ssklower ASSERT( tpcb->tp_lsuffixlen <= MAX_TSAP_SEL_LEN ); 424*37469Ssklower bcopy((caddr_t)tpcb->tp_lsuffix, value, tpcb->tp_lsuffixlen); 42536406Ssklower (*mp)->m_len = tpcb->tp_lsuffixlen; 42636406Ssklower } else /* cmd == PRCO_SETOPT */ { 42736406Ssklower if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { 42836406Ssklower printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); 42936406Ssklower error = EINVAL; 43036406Ssklower } else { 431*37469Ssklower bcopy(value, (caddr_t)tpcb->tp_lsuffix, val_len); 43236406Ssklower tpcb->tp_lsuffixlen = val_len; 43336406Ssklower } 43436406Ssklower } 43536406Ssklower break; 43636406Ssklower 43736406Ssklower case TPOPT_PEER_TSEL: 43836406Ssklower if ( cmd == PRCO_GETOPT ) { 43936406Ssklower ASSERT( tpcb->tp_fsuffixlen <= MAX_TSAP_SEL_LEN ); 440*37469Ssklower bcopy((caddr_t)tpcb->tp_fsuffix, value, tpcb->tp_fsuffixlen); 44136406Ssklower (*mp)->m_len = tpcb->tp_fsuffixlen; 44236406Ssklower } else /* cmd == PRCO_SETOPT */ { 44336406Ssklower if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { 44436406Ssklower printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); 44536406Ssklower error = EINVAL; 44636406Ssklower } else { 447*37469Ssklower bcopy(value, (caddr_t)tpcb->tp_fsuffix, val_len); 44836406Ssklower tpcb->tp_fsuffixlen = val_len; 44936406Ssklower } 45036406Ssklower } 45136406Ssklower break; 45236406Ssklower 45336406Ssklower case TPOPT_FLAGS: 45436406Ssklower IFDEBUG(D_REQUEST) 45536406Ssklower printf("%s TPOPT_FLAGS value 0x%x *value 0x%x, flags 0x%x \n", 45636406Ssklower cmd==PRCO_GETOPT?"GET":"SET", 45736406Ssklower value, 45836406Ssklower *value, 45936406Ssklower tpcb->tp_flags); 46036406Ssklower ENDDEBUG 46136406Ssklower 46236406Ssklower if ( cmd == PRCO_GETOPT ) { 46336406Ssklower *(int *)value = (int)tpcb->tp_flags; 46436406Ssklower (*mp)->m_len = sizeof(u_int); 46536406Ssklower } else /* cmd == PRCO_SETOPT */ { 46636406Ssklower error = EINVAL; goto done; 46736406Ssklower } 46836406Ssklower break; 46936406Ssklower 47036406Ssklower case TPOPT_PARAMS: 47136406Ssklower /* This handles: 47236406Ssklower * timer values, 47336406Ssklower * class, use of transport expedited data, 47436406Ssklower * max tpdu size, checksum, xtd format and 47536406Ssklower * disconnect indications, and may get rid of connect/disc data 47636406Ssklower */ 47736406Ssklower IFDEBUG(D_SETPARAMS) 47836406Ssklower printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, 47936406Ssklower cmd==PRCO_GETOPT?"GET":"SET"); 48036406Ssklower ENDDEBUG 48136406Ssklower IFDEBUG(D_REQUEST) 48236406Ssklower printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, 48336406Ssklower cmd==PRCO_GETOPT?"GET":"SET"); 48436406Ssklower ENDDEBUG 48536406Ssklower 48636406Ssklower if ( cmd == PRCO_GETOPT ) { 48736406Ssklower *(struct tp_conn_param *)value = tpcb->_tp_param; 48836406Ssklower (*mp)->m_len = sizeof(tpcb->_tp_param); 48936406Ssklower } else /* cmd == PRCO_SETOPT */ { 49036406Ssklower if( (error = 49136406Ssklower tp_consistency(tpcb, TP_STRICT | TP_FORCE, 49236406Ssklower (struct tp_conn_param *)value))==0) { 49336406Ssklower /* 49436406Ssklower * tp_consistency doesn't copy the whole set of params 49536406Ssklower */ 49636406Ssklower tpcb->_tp_param = *(struct tp_conn_param *)value; 49736406Ssklower (*mp)->m_len = sizeof(tpcb->_tp_param); 49836406Ssklower } 49936406Ssklower } 50036406Ssklower break; 50136406Ssklower 50236406Ssklower case TPOPT_PSTATISTICS: 50336406Ssklower #ifdef TP_PERF_MEAS 50436406Ssklower if (cmd == PRCO_SETOPT) { 50536406Ssklower error = EINVAL; goto done; 50636406Ssklower } 50736406Ssklower IFPERF(tpcb) 508*37469Ssklower if (*mp) { 509*37469Ssklower struct mbuf * n; 510*37469Ssklower do { 511*37469Ssklower MFREE(*mp, n); 512*37469Ssklower *mp = n; 513*37469Ssklower } while (n); 514*37469Ssklower } 515*37469Ssklower *mp = m_copym(tpcb->tp_p_mbuf, (int)M_COPYALL, M_WAITOK); 51636406Ssklower ENDPERF 51736406Ssklower else { 51836406Ssklower error = EINVAL; goto done; 51936406Ssklower } 52036406Ssklower break; 52136406Ssklower #else 52236406Ssklower error = EOPNOTSUPP; 52336406Ssklower goto done; 52436406Ssklower #endif TP_PERF_MEAS 52536406Ssklower 52636406Ssklower case TPOPT_CDDATA_CLEAR: 52736406Ssklower if (cmd == PRCO_GETOPT) { 52836406Ssklower error = EINVAL; 52936406Ssklower } else { 530*37469Ssklower if (tpcb->tp_ucddata) { 531*37469Ssklower m_freem(tpcb->tp_ucddata); 532*37469Ssklower tpcb->tp_ucddata = 0; 53336406Ssklower } 53436406Ssklower } 53536406Ssklower break; 53636406Ssklower 53736406Ssklower case TPOPT_DISC_DATA: 53836406Ssklower /* drop through */ 53936406Ssklower /* sending is for debugging purposes only -- we don't pretend 54036406Ssklower * to support * data on connect or disconnect fully. It's a 54136406Ssklower * kludge at best. 54236406Ssklower * This data-on-connect is only for the active side. It's sort of 54336406Ssklower * meaningless on the passive side (because 54436406Ssklower * you can't reject a connect request based on the data 54536406Ssklower * arriving w/ the CR, this, and because you'd have to 54636406Ssklower * do this setsockopt system call for each accept). 54736406Ssklower * but you can use it if you want. 54836406Ssklower */ 54936406Ssklower case TPOPT_CONN_DATA: 55036406Ssklower if( tpcb->tp_class == TP_CLASS_0 ) { 55136406Ssklower error = EOPNOTSUPP; 55236406Ssklower break; 55336406Ssklower } 55436406Ssklower IFDEBUG(D_REQUEST) 55536406Ssklower printf("%s\n", optname==TPOPT_DISC_DATA?"DISC data":"CONN data"); 55636406Ssklower printf("m_len 0x%x, vallen 0x%x so_snd.cc 0x%x\n", 55736406Ssklower (*mp)->m_len, val_len, so->so_snd.sb_cc); 55836406Ssklower dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput: sosnd "); 55936406Ssklower ENDDEBUG 56036406Ssklower if (cmd == PRCO_SETOPT) { 561*37469Ssklower int len = tpcb->tp_ucddata ? tpcb->tp_ucddata->m_len : 0; 56236406Ssklower /* can append connect data in several calls */ 563*37469Ssklower if (len + val_len > 56436406Ssklower (optname==TPOPT_CONN_DATA?TP_MAX_CR_DATA:TP_MAX_DR_DATA) ) { 56536406Ssklower error = EMSGSIZE; goto done; 56636406Ssklower } 56736406Ssklower (*mp)->m_next = MNULL; 56836406Ssklower (*mp)->m_act = 0; 569*37469Ssklower if (tpcb->tp_ucddata) 570*37469Ssklower m_cat(tpcb->tp_ucddata, *mp); 571*37469Ssklower else 572*37469Ssklower tpcb->tp_ucddata = *mp; 57336406Ssklower IFDEBUG(D_REQUEST) 574*37469Ssklower dump_mbuf(tpcb->tp_ucddata, "tp_ctloutput after CONN_DATA"); 57536406Ssklower ENDDEBUG 57636406Ssklower IFTRACE(D_REQUEST) 57736406Ssklower tptrace(TPPTmisc,"C/D DATA: flags snd.sbcc val_len", 57836406Ssklower tpcb->tp_flags, so->so_snd.sb_cc,val_len,0); 57936406Ssklower ENDTRACE 58036406Ssklower *mp = MNULL; /* prevent sosetopt from freeing it! */ 58136406Ssklower } 58236406Ssklower break; 58336406Ssklower 58436406Ssklower case TPOPT_PERF_MEAS: 58536406Ssklower #ifdef TP_PERF_MEAS 58636406Ssklower if (cmd == PRCO_GETOPT) { 58736406Ssklower *value = (u_int)tpcb->tp_perf_on; 58836406Ssklower (*mp)->m_len = sizeof(u_int); 58936406Ssklower } else if (cmd == PRCO_SETOPT) { 59036406Ssklower (*mp)->m_len = 0; 59136406Ssklower if ((*value) != 0 && (*value) != 1 ) 59236406Ssklower error = EINVAL; 59336406Ssklower else tpcb->tp_perf_on = (*value); 59436406Ssklower } 59536406Ssklower if( tpcb->tp_perf_on ) 59636406Ssklower error = tp_setup_perf(tpcb); 59736406Ssklower #else TP_PERF_MEAS 59836406Ssklower error = EOPNOTSUPP; 59936406Ssklower #endif TP_PERF_MEAS 60036406Ssklower break; 60136406Ssklower 60236406Ssklower default: 60336406Ssklower error = EOPNOTSUPP; 60436406Ssklower } 60536406Ssklower 60636406Ssklower done: 60736406Ssklower IFDEBUG(D_REQUEST) 60836406Ssklower dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput sosnd at end"); 60936406Ssklower dump_mbuf(*mp, "tp_ctloutput *mp"); 61036406Ssklower ENDDEBUG 61136406Ssklower /* 61236406Ssklower * sigh: getsockopt looks only at m_len : all output data must 61336406Ssklower * reside in the first mbuf 61436406Ssklower */ 61536406Ssklower if ( error && (*mp) != MNULL ) 61636406Ssklower (*mp)->m_len = 0; 61736406Ssklower if( (*mp) != MNULL ) { 61836406Ssklower ASSERT ( m_compress(*mp, mp) <= MLEN ); 61936406Ssklower IFDEBUG(D_REQUEST) 62036406Ssklower dump_mbuf(*mp, "tp_ctloutput *mp after compress"); 62136406Ssklower ENDDEBUG 62236406Ssklower } 62336406Ssklower 62436406Ssklower splx(s); 62536406Ssklower return error; 62636406Ssklower } 627