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*44601Ssklower * @(#)tp_output.c 7.7 (Berkeley) 06/29/90 * 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" 4244424Ssklower #include "mbuf.h" 4336406Ssklower #include "systm.h" 4436406Ssklower #include "socket.h" 4536406Ssklower #include "socketvar.h" 4644424Ssklower #include "protosw.h" 4744424Ssklower #include "user.h" 4844424Ssklower #include "kernel.h" 4936406Ssklower #include "errno.h" 5036406Ssklower #include "time.h" 5137469Ssklower #include "tp_param.h" 5237469Ssklower #include "tp_user.h" 5337469Ssklower #include "tp_stat.h" 5437469Ssklower #include "tp_ip.h" 5544424Ssklower #include "tp_clnp.h" 5637469Ssklower #include "tp_timer.h" 5737469Ssklower #include "argo_debug.h" 5837469Ssklower #include "tp_pcb.h" 5937469Ssklower #include "tp_trace.h" 6036406Ssklower 6136406Ssklower #define USERFLAGSMASK_G 0x0f00643b 6236406Ssklower #define USERFLAGSMASK_S 0x0f000432 6336406Ssklower #define TPDUSIZESHIFT 24 6436406Ssklower #define CLASSHIFT 16 6536406Ssklower 6636406Ssklower /* 6736406Ssklower * NAME: tp_consistency() 6836406Ssklower * 6936406Ssklower * CALLED FROM: 7036406Ssklower * tp_ctloutput(), tp_input() 7136406Ssklower * 7236406Ssklower * FUNCTION and ARGUMENTS: 7336406Ssklower * Checks the consistency of options and tpdusize with class, 7436406Ssklower * using the parameters passed in via (param). 7536406Ssklower * (cmd) may be TP_STRICT or TP_FORCE or both. 7636406Ssklower * Force means it will set all the values in (tpcb) to those in 7736406Ssklower * the input arguements iff no errors were encountered. 7836406Ssklower * Strict means that no inconsistency will be tolerated. If it's 7936406Ssklower * not used, checksum and tpdusize inconsistencies will be tolerated. 8036406Ssklower * The reason for this is that in some cases, when we're negotiating down 8136406Ssklower * from class 4, these options should be changed but should not 8236406Ssklower * cause negotiation to fail. 8336406Ssklower * 8436406Ssklower * RETURNS 8536406Ssklower * E* or EOK 8636406Ssklower * E* if the various parms aren't ok for a given class 8736406Ssklower * EOK if they are ok for a given class 8836406Ssklower */ 8936406Ssklower 9036406Ssklower int 9136406Ssklower tp_consistency( tpcb, cmd, param ) 9236406Ssklower u_int cmd; 9336406Ssklower struct tp_conn_param *param; 9436406Ssklower struct tp_pcb *tpcb; 9536406Ssklower { 9636406Ssklower register int error = EOK; 9736406Ssklower int class_to_use = tp_mask_to_num(param->p_class); 9836406Ssklower 9936406Ssklower IFTRACE(D_SETPARAMS) 10036406Ssklower tptrace(TPPTmisc, 10136406Ssklower "tp_consist enter class_to_use dontchange param.class cmd", 10236406Ssklower class_to_use, param->p_dont_change_params, param->p_class, cmd); 10336406Ssklower ENDTRACE 10436406Ssklower IFDEBUG(D_SETPARAMS) 10536406Ssklower printf("tp_consistency %s %s\n", 10636406Ssklower cmd& TP_FORCE? "TP_FORCE": "", 10736406Ssklower cmd& TP_STRICT? "TP_STRICT":""); 10836406Ssklower ENDDEBUG 10936406Ssklower if ((cmd & TP_FORCE) && (param->p_dont_change_params)) { 11036406Ssklower cmd &= ~TP_FORCE; 11136406Ssklower } 11236406Ssklower /* can switch net services within a domain, but 11336406Ssklower * cannot switch domains 11436406Ssklower */ 11536406Ssklower switch( param->p_netservice) { 11636406Ssklower case ISO_CONS: 11736406Ssklower case ISO_CLNS: 11836406Ssklower case ISO_COSNS: 11936406Ssklower /* param->p_netservice in ISO DOMAIN */ 12036406Ssklower if(tpcb->tp_domain != AF_ISO ) { 12136406Ssklower error = EINVAL; goto done; 12236406Ssklower } 12336406Ssklower break; 12436406Ssklower case IN_CLNS: 12536406Ssklower /* param->p_netservice in INET DOMAIN */ 12636406Ssklower if( tpcb->tp_domain != AF_INET ) { 12736406Ssklower error = EINVAL; goto done; 12836406Ssklower } 12936406Ssklower break; 13036406Ssklower /* no others not possible-> netservice is a 2-bit field! */ 13136406Ssklower } 13236406Ssklower 13336406Ssklower IFDEBUG(D_SETPARAMS) 13436406Ssklower printf("p_class 0x%x, class_to_use 0x%x\n", param->p_class, 13536406Ssklower class_to_use); 13636406Ssklower ENDDEBUG 13736406Ssklower if((param->p_netservice < 0) || (param->p_netservice > TP_MAX_NETSERVICES)){ 13836406Ssklower error = EINVAL; goto done; 13936406Ssklower } 14036406Ssklower if( (param->p_class & TP_CLASSES_IMPLEMENTED) == 0 ) { 14136406Ssklower error = EINVAL; goto done; 14236406Ssklower } 14336406Ssklower IFDEBUG(D_SETPARAMS) 14436406Ssklower printf("Nretrans 0x%x\n", param->p_Nretrans ); 14536406Ssklower ENDDEBUG 14636406Ssklower if( ( param->p_Nretrans < 1 ) || 14736406Ssklower (param->p_cr_ticks < 1) || (param->p_cc_ticks < 1) ) { 14836406Ssklower /* bad for any class because negot has to be done a la class 4 */ 14936406Ssklower error = EINVAL; goto done; 15036406Ssklower } 15136406Ssklower IFDEBUG(D_SETPARAMS) 15236406Ssklower printf("winsize 0x%x\n", param->p_winsize ); 15336406Ssklower ENDDEBUG 15436406Ssklower if( (param->p_winsize < 128 ) || 15536406Ssklower (param->p_winsize < param->p_tpdusize ) || 15636406Ssklower (param->p_winsize > ((1+SB_MAX)>>2 /* 1/4 of the max */)) ) { 15736406Ssklower error = EINVAL; goto done; 15836406Ssklower } else { 15936406Ssklower if( tpcb->tp_state == TP_CLOSED ) 16037469Ssklower soreserve(tpcb->tp_sock, (u_long)param->p_winsize, 16137469Ssklower (u_long)param->p_winsize); 16236406Ssklower } 16336406Ssklower IFDEBUG(D_SETPARAMS) 16436406Ssklower printf("use_csum 0x%x\n", param->p_use_checksum ); 16536406Ssklower printf("xtd_format 0x%x\n", param->p_xtd_format ); 16636406Ssklower printf("xpd_service 0x%x\n", param->p_xpd_service ); 16736406Ssklower printf("tpdusize 0x%x\n", param->p_tpdusize ); 16836406Ssklower printf("tpcb->flags 0x%x\n", tpcb->tp_flags ); 16936406Ssklower ENDDEBUG 17036406Ssklower switch( class_to_use ) { 17136406Ssklower 17236406Ssklower case 0: 17336406Ssklower /* do not use checksums, xtd format, or XPD */ 17436406Ssklower 17536406Ssklower if( param->p_use_checksum | param->p_xtd_format | param->p_xpd_service ) { 17636406Ssklower if(cmd & TP_STRICT) { 17736406Ssklower error = EINVAL; 17836406Ssklower } else { 17936406Ssklower param->p_use_checksum = 0; 18036406Ssklower param->p_xtd_format = 0; 18136406Ssklower param->p_xpd_service = 0; 18236406Ssklower } 18336406Ssklower break; 18436406Ssklower } 18536406Ssklower 18636406Ssklower if (param->p_tpdusize < TP_MIN_TPDUSIZE) { 18736406Ssklower if(cmd & TP_STRICT) { 18836406Ssklower error = EINVAL; 18936406Ssklower } else { 19036406Ssklower param->p_tpdusize = TP_MIN_TPDUSIZE; 19136406Ssklower } 19236406Ssklower break; 19336406Ssklower } 19436406Ssklower if (param->p_tpdusize > TP0_TPDUSIZE) { 19536406Ssklower if (cmd & TP_STRICT) { 19636406Ssklower error = EINVAL; 19736406Ssklower } else { 19836406Ssklower param->p_tpdusize = TP0_TPDUSIZE; 19936406Ssklower } 20036406Ssklower break; 20136406Ssklower } 20236406Ssklower 20336406Ssklower /* connect/disc data not allowed for class 0 */ 20437469Ssklower if (tpcb->tp_ucddata) { 20536406Ssklower if(cmd & TP_STRICT) { 20636406Ssklower error = EINVAL; 20736406Ssklower } else if(cmd & TP_FORCE) { 20837469Ssklower m_freem(tpcb->tp_ucddata); 20937469Ssklower tpcb->tp_ucddata = 0; 21036406Ssklower } 21136406Ssklower } 21236406Ssklower break; 21336406Ssklower 21436406Ssklower case 4: 21536406Ssklower IFDEBUG(D_SETPARAMS) 21636406Ssklower printf("dt_ticks 0x%x\n", param->p_dt_ticks ); 21736406Ssklower printf("x_ticks 0x%x\n", param->p_x_ticks ); 21836406Ssklower printf("dr_ticks 0x%x\n", param->p_dr_ticks ); 21936406Ssklower printf("keepalive 0x%x\n", param->p_keepalive_ticks ); 22036406Ssklower printf("sendack 0x%x\n", param->p_sendack_ticks ); 22136406Ssklower printf("inact 0x%x\n", param->p_inact_ticks ); 22236406Ssklower printf("ref 0x%x\n", param->p_ref_ticks ); 22336406Ssklower ENDDEBUG 22436406Ssklower if( (param->p_class & TP_CLASS_4 ) && ( 22536406Ssklower (param->p_dt_ticks < 1) || (param->p_dr_ticks < 1) || 22636406Ssklower (param->p_x_ticks < 1) || (param->p_keepalive_ticks < 1) || 22736406Ssklower (param->p_sendack_ticks < 1) || (param->p_ref_ticks < 1) || 22836406Ssklower (param->p_inact_ticks < 1) ) ) { 22936406Ssklower error = EINVAL; 23036406Ssklower break; 23136406Ssklower } 23236406Ssklower IFDEBUG(D_SETPARAMS) 23336406Ssklower printf("rx_strat 0x%x\n", param->p_rx_strat ); 23436406Ssklower ENDDEBUG 23536406Ssklower if(param->p_rx_strat > 23636406Ssklower ( TPRX_USE_CW | TPRX_EACH | TPRX_FASTSTART) ) { 23736406Ssklower if(cmd & TP_STRICT) { 23836406Ssklower error = EINVAL; 23936406Ssklower } else { 24036406Ssklower param->p_rx_strat = TPRX_USE_CW; 24136406Ssklower } 24236406Ssklower break; 24336406Ssklower } 24436406Ssklower IFDEBUG(D_SETPARAMS) 24536406Ssklower printf("ack_strat 0x%x\n", param->p_ack_strat ); 24636406Ssklower ENDDEBUG 24736406Ssklower if((param->p_ack_strat != 0) && (param->p_ack_strat != 1)) { 24836406Ssklower if(cmd & TP_STRICT) { 24936406Ssklower error = EINVAL; 25036406Ssklower } else { 25136406Ssklower param->p_ack_strat = TPACK_WINDOW; 25236406Ssklower } 25336406Ssklower break; 25436406Ssklower } 25536406Ssklower if (param->p_tpdusize < TP_MIN_TPDUSIZE) { 25636406Ssklower if(cmd & TP_STRICT) { 25736406Ssklower error = EINVAL; 25836406Ssklower } else { 25936406Ssklower param->p_tpdusize = TP_MIN_TPDUSIZE; 26036406Ssklower } 26136406Ssklower break; 26236406Ssklower } 26336406Ssklower if (param->p_tpdusize > TP_TPDUSIZE) { 26436406Ssklower if(cmd & TP_STRICT) { 26536406Ssklower error = EINVAL; 26636406Ssklower } else { 26736406Ssklower param->p_tpdusize = TP_TPDUSIZE; 26836406Ssklower } 26936406Ssklower break; 27036406Ssklower } 27136406Ssklower break; 27236406Ssklower } 27336406Ssklower 27436406Ssklower if ((error==0) && (cmd & TP_FORCE)) { 27536406Ssklower tpcb->tp_tpdusize = param->p_tpdusize; 27636406Ssklower tpcb->tp_class = param->p_class; 27736406Ssklower tpcb->tp_use_checksum = param->p_use_checksum; 27836406Ssklower tpcb->tp_xpd_service = param->p_xpd_service; 27936406Ssklower tpcb->tp_xtd_format = param->p_xtd_format; 28036406Ssklower } 28136406Ssklower 28236406Ssklower done: 28336406Ssklower 28436406Ssklower IFTRACE(D_CONN) 28536406Ssklower tptrace(TPPTmisc, "tp_consist returns class xtdfmt cmd", 28636406Ssklower error, tpcb->tp_class, tpcb->tp_xtd_format, cmd); 28736406Ssklower ENDTRACE 28836406Ssklower IFDEBUG(D_CONN) 28936406Ssklower printf( 29036406Ssklower "tp_consist rtns 0x%x class 0x%x xtd_fmt 0x%x cmd 0x%x\n", 29136406Ssklower error, tpcb->tp_class, tpcb->tp_xtd_format, cmd); 29236406Ssklower ENDDEBUG 29336406Ssklower return error; 29436406Ssklower } 29536406Ssklower 29636406Ssklower /* 29736406Ssklower * NAME: tp_ctloutput() 29836406Ssklower * 29936406Ssklower * CALLED FROM: 30036406Ssklower * [sg]etsockopt(), via so[sg]etopt(). 30136406Ssklower * 30236406Ssklower * FUNCTION and ARGUMENTS: 30336406Ssklower * Implements the socket options at transport level. 30437536Smckusick * (cmd) is either PRCO_SETOPT or PRCO_GETOPT (see ../sys/protosw.h). 30536406Ssklower * (so) is the socket. 30637536Smckusick * (level) is SOL_TRANSPORT (see ../sys/socket.h) 30736406Ssklower * (optname) is the particular command or option to be set. 30836406Ssklower * (**mp) is an mbuf structure. 30936406Ssklower * 31036406Ssklower * RETURN VALUE: 31136406Ssklower * ENOTSOCK if the socket hasn't got an associated tpcb 31236406Ssklower * EINVAL if 31336406Ssklower * trying to set window too big 31436406Ssklower * trying to set illegal max tpdu size 31536406Ssklower * trying to set illegal credit fraction 31636406Ssklower * trying to use unknown or unimplemented class of TP 31736406Ssklower * structure passed to set timer values is wrong size 31836406Ssklower * illegal combination of command/GET-SET option, 31936406Ssklower * e.g., GET w/ TPOPT_CDDATA_CLEAR: 32036406Ssklower * EOPNOTSUPP if the level isn't transport, or command is neither GET nor SET 32136406Ssklower * or if the transport-specific command is not implemented 32236406Ssklower * EISCONN if trying a command that isn't allowed after a connection 32336406Ssklower * is established 32436406Ssklower * ENOTCONN if trying a command that is allowed only if a connection is 32536406Ssklower * established 32636406Ssklower * EMSGSIZE if trying to give too much data on connect/disconnect 32736406Ssklower * 32836406Ssklower * SIDE EFFECTS: 32936406Ssklower * 33036406Ssklower * NOTES: 33136406Ssklower */ 33236406Ssklower ProtoHook 33336406Ssklower tp_ctloutput(cmd, so, level, optname, mp) 33436406Ssklower int cmd, level, optname; 33536406Ssklower struct socket *so; 33636406Ssklower struct mbuf **mp; 33736406Ssklower { 33836406Ssklower struct tp_pcb *tpcb = sototpcb(so); 33936406Ssklower int s = splnet(); 34037469Ssklower caddr_t value; 34137469Ssklower unsigned val_len; 34236406Ssklower int error = 0; 34336406Ssklower 34436406Ssklower IFTRACE(D_REQUEST) 34536406Ssklower tptrace(TPPTmisc, "tp_ctloutput cmd so optname mp", 34636406Ssklower cmd, so, optname, mp); 34736406Ssklower ENDTRACE 34836406Ssklower IFDEBUG(D_REQUEST) 34936406Ssklower printf( 35036406Ssklower "tp_ctloutput so 0x%x cmd 0x%x optname 0x%x, mp 0x%x *mp 0x%x tpcb 0x%x\n", 35136406Ssklower so, cmd, optname, mp, mp?*mp:0, tpcb); 35236406Ssklower ENDDEBUG 35336406Ssklower if( tpcb == (struct tp_pcb *)0 ) { 35436406Ssklower error = ENOTSOCK; goto done; 35536406Ssklower } 35636406Ssklower if(*mp == MNULL) { 35736406Ssklower register struct mbuf *m; 35836406Ssklower 35936406Ssklower MGET(m, M_DONTWAIT, TPMT_SONAME); /* does off, type, next */ 36036406Ssklower if (m == NULL) { 36136406Ssklower splx(s); 36236406Ssklower return ENOBUFS; 36336406Ssklower } 36436406Ssklower m->m_len = 0; 36536406Ssklower m->m_act = 0; 36636406Ssklower *mp = m; 36736406Ssklower } 36836406Ssklower 36936406Ssklower /* 37036406Ssklower * Hook so one can set network options via a tp socket. 37136406Ssklower */ 37236406Ssklower if ( level == SOL_NETWORK ) { 37336406Ssklower if ((tpcb->tp_nlproto == NULL) || (tpcb->tp_npcb == NULL)) 37436406Ssklower error = ENOTSOCK; 37536406Ssklower else if (tpcb->tp_nlproto->nlp_ctloutput == NULL) 37636406Ssklower error = EOPNOTSUPP; 37736406Ssklower else 37836406Ssklower error = (tpcb->tp_nlproto->nlp_ctloutput)(cmd, optname, 37936406Ssklower tpcb->tp_npcb, *mp); 38036406Ssklower goto done; 38136406Ssklower } else if ( level != SOL_TRANSPORT ) { 38236406Ssklower error = EOPNOTSUPP; goto done; 38336406Ssklower } 38436406Ssklower if (cmd != PRCO_GETOPT && cmd != PRCO_SETOPT) { 38536406Ssklower error = EOPNOTSUPP; goto done; 38636406Ssklower } 38736406Ssklower if ( so->so_error ) { 38836406Ssklower error = so->so_error; goto done; 38936406Ssklower } 39036406Ssklower 39136406Ssklower /* The only options allowed after connection is established 39236406Ssklower * are GET (anything) and SET DISC DATA and SET PERF MEAS 39336406Ssklower */ 39436406Ssklower if ( ((so->so_state & SS_ISCONNECTING)||(so->so_state & SS_ISCONNECTED)) 39536406Ssklower && 39636406Ssklower (cmd == PRCO_SETOPT && 39736406Ssklower optname != TPOPT_DISC_DATA && 39838841Ssklower optname != TPOPT_CFRM_DATA && 39936406Ssklower optname != TPOPT_PERF_MEAS && 40036406Ssklower optname != TPOPT_CDDATA_CLEAR ) ) { 40136406Ssklower error = EISCONN; goto done; 40236406Ssklower } 40336406Ssklower /* The only options allowed after disconnection are GET DISC DATA, 40436406Ssklower * and TPOPT_PSTATISTICS 40536406Ssklower * and they're not allowed if the ref timer has gone off, because 40636406Ssklower * the tpcb is gone 40736406Ssklower */ 40838841Ssklower if ((so->so_state & (SS_ISCONNECTED | SS_ISCONFIRMING)) == 0) { 40936406Ssklower if ( so->so_tpcb == (caddr_t)0 ) { 41036406Ssklower error = ENOTCONN; goto done; 41136406Ssklower } 41236406Ssklower if ( (tpcb->tp_state == TP_REFWAIT || tpcb->tp_state == TP_CLOSING) && 41336406Ssklower (optname != TPOPT_DISC_DATA && optname != TPOPT_PSTATISTICS)) { 41436406Ssklower error = ENOTCONN; goto done; 41536406Ssklower } 41636406Ssklower } 41736406Ssklower 41837469Ssklower value = mtod(*mp, caddr_t); /* it's aligned, don't worry, 41937469Ssklower * but lint complains about it 42037469Ssklower */ 42136406Ssklower val_len = (*mp)->m_len; 42236406Ssklower 42336406Ssklower switch (optname) { 42436406Ssklower 42544424Ssklower case TPOPT_INTERCEPT: 42644424Ssklower if (error = suser(u.u_cred, &u.u_acflag)) 42744424Ssklower break; 42844424Ssklower else if (cmd != PRCO_SETOPT || tpcb->tp_state != TP_LISTENING) 42944424Ssklower error = EINVAL; 43044424Ssklower else { 43144424Ssklower register struct tp_pcb *t = 0; 43244424Ssklower struct mbuf *m = m_getclr(M_WAIT, MT_SONAME); 43344424Ssklower struct sockaddr *sa = mtod(m, struct sockaddr *); 43444424Ssklower (*tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, m, TP_LOCAL); 43544424Ssklower switch (sa->sa_family) { 43644424Ssklower case AF_ISO: 43744424Ssklower if (((struct sockaddr_iso *)sa)->siso_nlen == 0) 43844424Ssklower default: error = EINVAL; 43944424Ssklower break; 44044424Ssklower case AF_INET: 44144424Ssklower if (((struct sockaddr_in *)sa)->sin_addr.s_addr == 0) 44244424Ssklower error = EINVAL; 44344424Ssklower break; 44444424Ssklower } 44544424Ssklower for (t = tp_intercepts; t; t = t->tp_nextlisten) { 44644424Ssklower if (t->tp_nlproto->nlp_afamily != tpcb->tp_nlproto->nlp_afamily) 44744424Ssklower continue; 44844424Ssklower if ((*t->tp_nlproto->nlp_cmpnetaddr)(t->tp_npcb, sa, TP_LOCAL)) 44944424Ssklower error = EADDRINUSE; 45044424Ssklower } 45144424Ssklower m_freem(m); 45244424Ssklower if (error) 45344424Ssklower break; 45444424Ssklower } 45544424Ssklower { 45644424Ssklower register struct tp_pcb **tt; 45744424Ssklower for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten)) 45844424Ssklower if (*tt == tpcb) 45944424Ssklower break; 46044424Ssklower if (*tt) 46144424Ssklower *tt = tpcb->tp_nextlisten; 46244424Ssklower else 46344424Ssklower {error = EHOSTUNREACH; goto done; } 46444424Ssklower } 465*44601Ssklower tpcb->tp_nextlisten = tp_intercepts; 46644424Ssklower tp_intercepts = tpcb; 46744424Ssklower break; 46844424Ssklower 46936406Ssklower case TPOPT_MY_TSEL: 47036406Ssklower if ( cmd == PRCO_GETOPT ) { 47136406Ssklower ASSERT( tpcb->tp_lsuffixlen <= MAX_TSAP_SEL_LEN ); 47237469Ssklower bcopy((caddr_t)tpcb->tp_lsuffix, value, tpcb->tp_lsuffixlen); 47336406Ssklower (*mp)->m_len = tpcb->tp_lsuffixlen; 47436406Ssklower } else /* cmd == PRCO_SETOPT */ { 47536406Ssklower if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { 47636406Ssklower printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); 47736406Ssklower error = EINVAL; 47836406Ssklower } else { 47937469Ssklower bcopy(value, (caddr_t)tpcb->tp_lsuffix, val_len); 48036406Ssklower tpcb->tp_lsuffixlen = val_len; 48136406Ssklower } 48236406Ssklower } 48336406Ssklower break; 48436406Ssklower 48536406Ssklower case TPOPT_PEER_TSEL: 48636406Ssklower if ( cmd == PRCO_GETOPT ) { 48736406Ssklower ASSERT( tpcb->tp_fsuffixlen <= MAX_TSAP_SEL_LEN ); 48837469Ssklower bcopy((caddr_t)tpcb->tp_fsuffix, value, tpcb->tp_fsuffixlen); 48936406Ssklower (*mp)->m_len = tpcb->tp_fsuffixlen; 49036406Ssklower } else /* cmd == PRCO_SETOPT */ { 49136406Ssklower if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { 49236406Ssklower printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); 49336406Ssklower error = EINVAL; 49436406Ssklower } else { 49537469Ssklower bcopy(value, (caddr_t)tpcb->tp_fsuffix, val_len); 49636406Ssklower tpcb->tp_fsuffixlen = val_len; 49736406Ssklower } 49836406Ssklower } 49936406Ssklower break; 50036406Ssklower 50136406Ssklower case TPOPT_FLAGS: 50236406Ssklower IFDEBUG(D_REQUEST) 50336406Ssklower printf("%s TPOPT_FLAGS value 0x%x *value 0x%x, flags 0x%x \n", 50436406Ssklower cmd==PRCO_GETOPT?"GET":"SET", 50536406Ssklower value, 50636406Ssklower *value, 50736406Ssklower tpcb->tp_flags); 50836406Ssklower ENDDEBUG 50936406Ssklower 51036406Ssklower if ( cmd == PRCO_GETOPT ) { 51136406Ssklower *(int *)value = (int)tpcb->tp_flags; 51236406Ssklower (*mp)->m_len = sizeof(u_int); 51336406Ssklower } else /* cmd == PRCO_SETOPT */ { 51436406Ssklower error = EINVAL; goto done; 51536406Ssklower } 51636406Ssklower break; 51736406Ssklower 51836406Ssklower case TPOPT_PARAMS: 51936406Ssklower /* This handles: 52036406Ssklower * timer values, 52136406Ssklower * class, use of transport expedited data, 52236406Ssklower * max tpdu size, checksum, xtd format and 52336406Ssklower * disconnect indications, and may get rid of connect/disc data 52436406Ssklower */ 52536406Ssklower IFDEBUG(D_SETPARAMS) 52636406Ssklower printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, 52736406Ssklower cmd==PRCO_GETOPT?"GET":"SET"); 52836406Ssklower ENDDEBUG 52936406Ssklower IFDEBUG(D_REQUEST) 53036406Ssklower printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, 53136406Ssklower cmd==PRCO_GETOPT?"GET":"SET"); 53236406Ssklower ENDDEBUG 53336406Ssklower 53436406Ssklower if ( cmd == PRCO_GETOPT ) { 53536406Ssklower *(struct tp_conn_param *)value = tpcb->_tp_param; 53636406Ssklower (*mp)->m_len = sizeof(tpcb->_tp_param); 53736406Ssklower } else /* cmd == PRCO_SETOPT */ { 53836406Ssklower if( (error = 53936406Ssklower tp_consistency(tpcb, TP_STRICT | TP_FORCE, 54036406Ssklower (struct tp_conn_param *)value))==0) { 54136406Ssklower /* 54236406Ssklower * tp_consistency doesn't copy the whole set of params 54336406Ssklower */ 54436406Ssklower tpcb->_tp_param = *(struct tp_conn_param *)value; 54536406Ssklower (*mp)->m_len = sizeof(tpcb->_tp_param); 54636406Ssklower } 54736406Ssklower } 54836406Ssklower break; 54936406Ssklower 55036406Ssklower case TPOPT_PSTATISTICS: 55136406Ssklower #ifdef TP_PERF_MEAS 55236406Ssklower if (cmd == PRCO_SETOPT) { 55336406Ssklower error = EINVAL; goto done; 55436406Ssklower } 55536406Ssklower IFPERF(tpcb) 55637469Ssklower if (*mp) { 55737469Ssklower struct mbuf * n; 55837469Ssklower do { 55937469Ssklower MFREE(*mp, n); 56037469Ssklower *mp = n; 56137469Ssklower } while (n); 56237469Ssklower } 56337469Ssklower *mp = m_copym(tpcb->tp_p_mbuf, (int)M_COPYALL, M_WAITOK); 56436406Ssklower ENDPERF 56536406Ssklower else { 56636406Ssklower error = EINVAL; goto done; 56736406Ssklower } 56836406Ssklower break; 56936406Ssklower #else 57036406Ssklower error = EOPNOTSUPP; 57136406Ssklower goto done; 57236406Ssklower #endif TP_PERF_MEAS 57336406Ssklower 57436406Ssklower case TPOPT_CDDATA_CLEAR: 57536406Ssklower if (cmd == PRCO_GETOPT) { 57636406Ssklower error = EINVAL; 57736406Ssklower } else { 57837469Ssklower if (tpcb->tp_ucddata) { 57938841Ssklower m_freem(tpcb->tp_ucddata); 58038841Ssklower tpcb->tp_ucddata = 0; 58136406Ssklower } 58236406Ssklower } 58336406Ssklower break; 58436406Ssklower 58538841Ssklower case TPOPT_CFRM_DATA: 58636406Ssklower case TPOPT_DISC_DATA: 58736406Ssklower case TPOPT_CONN_DATA: 58836406Ssklower if( tpcb->tp_class == TP_CLASS_0 ) { 58936406Ssklower error = EOPNOTSUPP; 59036406Ssklower break; 59136406Ssklower } 59236406Ssklower IFDEBUG(D_REQUEST) 59336406Ssklower printf("%s\n", optname==TPOPT_DISC_DATA?"DISC data":"CONN data"); 59436406Ssklower printf("m_len 0x%x, vallen 0x%x so_snd.cc 0x%x\n", 59536406Ssklower (*mp)->m_len, val_len, so->so_snd.sb_cc); 59636406Ssklower dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput: sosnd "); 59736406Ssklower ENDDEBUG 59836406Ssklower if (cmd == PRCO_SETOPT) { 59937469Ssklower int len = tpcb->tp_ucddata ? tpcb->tp_ucddata->m_len : 0; 60036406Ssklower /* can append connect data in several calls */ 60137469Ssklower if (len + val_len > 60236406Ssklower (optname==TPOPT_CONN_DATA?TP_MAX_CR_DATA:TP_MAX_DR_DATA) ) { 60336406Ssklower error = EMSGSIZE; goto done; 60436406Ssklower } 60536406Ssklower (*mp)->m_next = MNULL; 60636406Ssklower (*mp)->m_act = 0; 60737469Ssklower if (tpcb->tp_ucddata) 60837469Ssklower m_cat(tpcb->tp_ucddata, *mp); 60937469Ssklower else 61037469Ssklower tpcb->tp_ucddata = *mp; 61140241Ssklower IFDEBUG(D_REQUEST) 61240241Ssklower dump_mbuf(tpcb->tp_ucddata, "tp_ctloutput after CONN_DATA"); 61340241Ssklower ENDDEBUG 61436406Ssklower IFTRACE(D_REQUEST) 61536406Ssklower tptrace(TPPTmisc,"C/D DATA: flags snd.sbcc val_len", 61636406Ssklower tpcb->tp_flags, so->so_snd.sb_cc,val_len,0); 61736406Ssklower ENDTRACE 61836406Ssklower *mp = MNULL; /* prevent sosetopt from freeing it! */ 61940241Ssklower if (optname == TPOPT_CFRM_DATA && (so->so_state & SS_ISCONFIRMING)) 62040241Ssklower (void) tp_confirm(tpcb); 62136406Ssklower } 62236406Ssklower break; 62336406Ssklower 62436406Ssklower case TPOPT_PERF_MEAS: 62536406Ssklower #ifdef TP_PERF_MEAS 62636406Ssklower if (cmd == PRCO_GETOPT) { 62736406Ssklower *value = (u_int)tpcb->tp_perf_on; 62836406Ssklower (*mp)->m_len = sizeof(u_int); 62936406Ssklower } else if (cmd == PRCO_SETOPT) { 63036406Ssklower (*mp)->m_len = 0; 63136406Ssklower if ((*value) != 0 && (*value) != 1 ) 63236406Ssklower error = EINVAL; 63336406Ssklower else tpcb->tp_perf_on = (*value); 63436406Ssklower } 63536406Ssklower if( tpcb->tp_perf_on ) 63636406Ssklower error = tp_setup_perf(tpcb); 63736406Ssklower #else TP_PERF_MEAS 63836406Ssklower error = EOPNOTSUPP; 63936406Ssklower #endif TP_PERF_MEAS 64036406Ssklower break; 64136406Ssklower 64236406Ssklower default: 64336406Ssklower error = EOPNOTSUPP; 64436406Ssklower } 64536406Ssklower 64636406Ssklower done: 64736406Ssklower IFDEBUG(D_REQUEST) 64836406Ssklower dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput sosnd at end"); 64936406Ssklower dump_mbuf(*mp, "tp_ctloutput *mp"); 65036406Ssklower ENDDEBUG 65136406Ssklower /* 65236406Ssklower * sigh: getsockopt looks only at m_len : all output data must 65336406Ssklower * reside in the first mbuf 65436406Ssklower */ 65536406Ssklower if ( error && (*mp) != MNULL ) 65636406Ssklower (*mp)->m_len = 0; 65736406Ssklower if( (*mp) != MNULL ) { 65836406Ssklower ASSERT ( m_compress(*mp, mp) <= MLEN ); 65936406Ssklower IFDEBUG(D_REQUEST) 66036406Ssklower dump_mbuf(*mp, "tp_ctloutput *mp after compress"); 66136406Ssklower ENDDEBUG 66236406Ssklower } 66336406Ssklower 66436406Ssklower splx(s); 66536406Ssklower return error; 66636406Ssklower } 667