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*47282Ssklower * @(#)tp_output.c 7.8 (Berkeley) 03/12/91 * 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)) { 275*47282Ssklower /* Enforce Negotation rules below */ 276*47282Ssklower if (tpcb->tp_tpdusize > param->p_tpdusize) 277*47282Ssklower tpcb->tp_tpdusize = param->p_tpdusize; 27836406Ssklower tpcb->tp_class = param->p_class; 279*47282Ssklower if (tpcb->tp_use_checksum || param->p_use_checksum) 280*47282Ssklower tpcb->tp_use_checksum = 1; 281*47282Ssklower if (!tpcb->tp_xpd_service || !param->p_xpd_service) 282*47282Ssklower tpcb->tp_xpd_service = 0; 283*47282Ssklower if (!tpcb->tp_xtd_format || !param->p_xtd_format) 284*47282Ssklower tpcb->tp_xtd_format = 0; 28536406Ssklower } 28636406Ssklower 28736406Ssklower done: 28836406Ssklower 28936406Ssklower IFTRACE(D_CONN) 29036406Ssklower tptrace(TPPTmisc, "tp_consist returns class xtdfmt cmd", 29136406Ssklower error, tpcb->tp_class, tpcb->tp_xtd_format, cmd); 29236406Ssklower ENDTRACE 29336406Ssklower IFDEBUG(D_CONN) 29436406Ssklower printf( 29536406Ssklower "tp_consist rtns 0x%x class 0x%x xtd_fmt 0x%x cmd 0x%x\n", 29636406Ssklower error, tpcb->tp_class, tpcb->tp_xtd_format, cmd); 29736406Ssklower ENDDEBUG 29836406Ssklower return error; 29936406Ssklower } 30036406Ssklower 30136406Ssklower /* 30236406Ssklower * NAME: tp_ctloutput() 30336406Ssklower * 30436406Ssklower * CALLED FROM: 30536406Ssklower * [sg]etsockopt(), via so[sg]etopt(). 30636406Ssklower * 30736406Ssklower * FUNCTION and ARGUMENTS: 30836406Ssklower * Implements the socket options at transport level. 30937536Smckusick * (cmd) is either PRCO_SETOPT or PRCO_GETOPT (see ../sys/protosw.h). 31036406Ssklower * (so) is the socket. 31137536Smckusick * (level) is SOL_TRANSPORT (see ../sys/socket.h) 31236406Ssklower * (optname) is the particular command or option to be set. 31336406Ssklower * (**mp) is an mbuf structure. 31436406Ssklower * 31536406Ssklower * RETURN VALUE: 31636406Ssklower * ENOTSOCK if the socket hasn't got an associated tpcb 31736406Ssklower * EINVAL if 31836406Ssklower * trying to set window too big 31936406Ssklower * trying to set illegal max tpdu size 32036406Ssklower * trying to set illegal credit fraction 32136406Ssklower * trying to use unknown or unimplemented class of TP 32236406Ssklower * structure passed to set timer values is wrong size 32336406Ssklower * illegal combination of command/GET-SET option, 32436406Ssklower * e.g., GET w/ TPOPT_CDDATA_CLEAR: 32536406Ssklower * EOPNOTSUPP if the level isn't transport, or command is neither GET nor SET 32636406Ssklower * or if the transport-specific command is not implemented 32736406Ssklower * EISCONN if trying a command that isn't allowed after a connection 32836406Ssklower * is established 32936406Ssklower * ENOTCONN if trying a command that is allowed only if a connection is 33036406Ssklower * established 33136406Ssklower * EMSGSIZE if trying to give too much data on connect/disconnect 33236406Ssklower * 33336406Ssklower * SIDE EFFECTS: 33436406Ssklower * 33536406Ssklower * NOTES: 33636406Ssklower */ 33736406Ssklower ProtoHook 33836406Ssklower tp_ctloutput(cmd, so, level, optname, mp) 33936406Ssklower int cmd, level, optname; 34036406Ssklower struct socket *so; 34136406Ssklower struct mbuf **mp; 34236406Ssklower { 34336406Ssklower struct tp_pcb *tpcb = sototpcb(so); 34436406Ssklower int s = splnet(); 34537469Ssklower caddr_t value; 34637469Ssklower unsigned val_len; 34736406Ssklower int error = 0; 34836406Ssklower 34936406Ssklower IFTRACE(D_REQUEST) 35036406Ssklower tptrace(TPPTmisc, "tp_ctloutput cmd so optname mp", 35136406Ssklower cmd, so, optname, mp); 35236406Ssklower ENDTRACE 35336406Ssklower IFDEBUG(D_REQUEST) 35436406Ssklower printf( 35536406Ssklower "tp_ctloutput so 0x%x cmd 0x%x optname 0x%x, mp 0x%x *mp 0x%x tpcb 0x%x\n", 35636406Ssklower so, cmd, optname, mp, mp?*mp:0, tpcb); 35736406Ssklower ENDDEBUG 35836406Ssklower if( tpcb == (struct tp_pcb *)0 ) { 35936406Ssklower error = ENOTSOCK; goto done; 36036406Ssklower } 36136406Ssklower if(*mp == MNULL) { 36236406Ssklower register struct mbuf *m; 36336406Ssklower 36436406Ssklower MGET(m, M_DONTWAIT, TPMT_SONAME); /* does off, type, next */ 36536406Ssklower if (m == NULL) { 36636406Ssklower splx(s); 36736406Ssklower return ENOBUFS; 36836406Ssklower } 36936406Ssklower m->m_len = 0; 37036406Ssklower m->m_act = 0; 37136406Ssklower *mp = m; 37236406Ssklower } 37336406Ssklower 37436406Ssklower /* 37536406Ssklower * Hook so one can set network options via a tp socket. 37636406Ssklower */ 37736406Ssklower if ( level == SOL_NETWORK ) { 37836406Ssklower if ((tpcb->tp_nlproto == NULL) || (tpcb->tp_npcb == NULL)) 37936406Ssklower error = ENOTSOCK; 38036406Ssklower else if (tpcb->tp_nlproto->nlp_ctloutput == NULL) 38136406Ssklower error = EOPNOTSUPP; 38236406Ssklower else 38336406Ssklower error = (tpcb->tp_nlproto->nlp_ctloutput)(cmd, optname, 38436406Ssklower tpcb->tp_npcb, *mp); 38536406Ssklower goto done; 38636406Ssklower } else if ( level != SOL_TRANSPORT ) { 38736406Ssklower error = EOPNOTSUPP; goto done; 38836406Ssklower } 38936406Ssklower if (cmd != PRCO_GETOPT && cmd != PRCO_SETOPT) { 39036406Ssklower error = EOPNOTSUPP; goto done; 39136406Ssklower } 39236406Ssklower if ( so->so_error ) { 39336406Ssklower error = so->so_error; goto done; 39436406Ssklower } 39536406Ssklower 39636406Ssklower /* The only options allowed after connection is established 39736406Ssklower * are GET (anything) and SET DISC DATA and SET PERF MEAS 39836406Ssklower */ 39936406Ssklower if ( ((so->so_state & SS_ISCONNECTING)||(so->so_state & SS_ISCONNECTED)) 40036406Ssklower && 40136406Ssklower (cmd == PRCO_SETOPT && 40236406Ssklower optname != TPOPT_DISC_DATA && 40338841Ssklower optname != TPOPT_CFRM_DATA && 40436406Ssklower optname != TPOPT_PERF_MEAS && 40536406Ssklower optname != TPOPT_CDDATA_CLEAR ) ) { 40636406Ssklower error = EISCONN; goto done; 40736406Ssklower } 40836406Ssklower /* The only options allowed after disconnection are GET DISC DATA, 40936406Ssklower * and TPOPT_PSTATISTICS 41036406Ssklower * and they're not allowed if the ref timer has gone off, because 41136406Ssklower * the tpcb is gone 41236406Ssklower */ 41338841Ssklower if ((so->so_state & (SS_ISCONNECTED | SS_ISCONFIRMING)) == 0) { 41436406Ssklower if ( so->so_tpcb == (caddr_t)0 ) { 41536406Ssklower error = ENOTCONN; goto done; 41636406Ssklower } 41736406Ssklower if ( (tpcb->tp_state == TP_REFWAIT || tpcb->tp_state == TP_CLOSING) && 41836406Ssklower (optname != TPOPT_DISC_DATA && optname != TPOPT_PSTATISTICS)) { 41936406Ssklower error = ENOTCONN; goto done; 42036406Ssklower } 42136406Ssklower } 42236406Ssklower 42337469Ssklower value = mtod(*mp, caddr_t); /* it's aligned, don't worry, 42437469Ssklower * but lint complains about it 42537469Ssklower */ 42636406Ssklower val_len = (*mp)->m_len; 42736406Ssklower 42836406Ssklower switch (optname) { 42936406Ssklower 43044424Ssklower case TPOPT_INTERCEPT: 43144424Ssklower if (error = suser(u.u_cred, &u.u_acflag)) 43244424Ssklower break; 43344424Ssklower else if (cmd != PRCO_SETOPT || tpcb->tp_state != TP_LISTENING) 43444424Ssklower error = EINVAL; 43544424Ssklower else { 43644424Ssklower register struct tp_pcb *t = 0; 43744424Ssklower struct mbuf *m = m_getclr(M_WAIT, MT_SONAME); 43844424Ssklower struct sockaddr *sa = mtod(m, struct sockaddr *); 43944424Ssklower (*tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, m, TP_LOCAL); 44044424Ssklower switch (sa->sa_family) { 44144424Ssklower case AF_ISO: 44244424Ssklower if (((struct sockaddr_iso *)sa)->siso_nlen == 0) 44344424Ssklower default: error = EINVAL; 44444424Ssklower break; 44544424Ssklower case AF_INET: 44644424Ssklower if (((struct sockaddr_in *)sa)->sin_addr.s_addr == 0) 44744424Ssklower error = EINVAL; 44844424Ssklower break; 44944424Ssklower } 45044424Ssklower for (t = tp_intercepts; t; t = t->tp_nextlisten) { 45144424Ssklower if (t->tp_nlproto->nlp_afamily != tpcb->tp_nlproto->nlp_afamily) 45244424Ssklower continue; 45344424Ssklower if ((*t->tp_nlproto->nlp_cmpnetaddr)(t->tp_npcb, sa, TP_LOCAL)) 45444424Ssklower error = EADDRINUSE; 45544424Ssklower } 45644424Ssklower m_freem(m); 45744424Ssklower if (error) 45844424Ssklower break; 45944424Ssklower } 46044424Ssklower { 46144424Ssklower register struct tp_pcb **tt; 46244424Ssklower for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten)) 46344424Ssklower if (*tt == tpcb) 46444424Ssklower break; 46544424Ssklower if (*tt) 46644424Ssklower *tt = tpcb->tp_nextlisten; 46744424Ssklower else 46844424Ssklower {error = EHOSTUNREACH; goto done; } 46944424Ssklower } 47044601Ssklower tpcb->tp_nextlisten = tp_intercepts; 47144424Ssklower tp_intercepts = tpcb; 47244424Ssklower break; 47344424Ssklower 47436406Ssklower case TPOPT_MY_TSEL: 47536406Ssklower if ( cmd == PRCO_GETOPT ) { 47636406Ssklower ASSERT( tpcb->tp_lsuffixlen <= MAX_TSAP_SEL_LEN ); 47737469Ssklower bcopy((caddr_t)tpcb->tp_lsuffix, value, tpcb->tp_lsuffixlen); 47836406Ssklower (*mp)->m_len = tpcb->tp_lsuffixlen; 47936406Ssklower } else /* cmd == PRCO_SETOPT */ { 48036406Ssklower if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { 48136406Ssklower printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); 48236406Ssklower error = EINVAL; 48336406Ssklower } else { 48437469Ssklower bcopy(value, (caddr_t)tpcb->tp_lsuffix, val_len); 48536406Ssklower tpcb->tp_lsuffixlen = val_len; 48636406Ssklower } 48736406Ssklower } 48836406Ssklower break; 48936406Ssklower 49036406Ssklower case TPOPT_PEER_TSEL: 49136406Ssklower if ( cmd == PRCO_GETOPT ) { 49236406Ssklower ASSERT( tpcb->tp_fsuffixlen <= MAX_TSAP_SEL_LEN ); 49337469Ssklower bcopy((caddr_t)tpcb->tp_fsuffix, value, tpcb->tp_fsuffixlen); 49436406Ssklower (*mp)->m_len = tpcb->tp_fsuffixlen; 49536406Ssklower } else /* cmd == PRCO_SETOPT */ { 49636406Ssklower if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { 49736406Ssklower printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); 49836406Ssklower error = EINVAL; 49936406Ssklower } else { 50037469Ssklower bcopy(value, (caddr_t)tpcb->tp_fsuffix, val_len); 50136406Ssklower tpcb->tp_fsuffixlen = val_len; 50236406Ssklower } 50336406Ssklower } 50436406Ssklower break; 50536406Ssklower 50636406Ssklower case TPOPT_FLAGS: 50736406Ssklower IFDEBUG(D_REQUEST) 50836406Ssklower printf("%s TPOPT_FLAGS value 0x%x *value 0x%x, flags 0x%x \n", 50936406Ssklower cmd==PRCO_GETOPT?"GET":"SET", 51036406Ssklower value, 51136406Ssklower *value, 51236406Ssklower tpcb->tp_flags); 51336406Ssklower ENDDEBUG 51436406Ssklower 51536406Ssklower if ( cmd == PRCO_GETOPT ) { 51636406Ssklower *(int *)value = (int)tpcb->tp_flags; 51736406Ssklower (*mp)->m_len = sizeof(u_int); 51836406Ssklower } else /* cmd == PRCO_SETOPT */ { 51936406Ssklower error = EINVAL; goto done; 52036406Ssklower } 52136406Ssklower break; 52236406Ssklower 52336406Ssklower case TPOPT_PARAMS: 52436406Ssklower /* This handles: 52536406Ssklower * timer values, 52636406Ssklower * class, use of transport expedited data, 52736406Ssklower * max tpdu size, checksum, xtd format and 52836406Ssklower * disconnect indications, and may get rid of connect/disc data 52936406Ssklower */ 53036406Ssklower IFDEBUG(D_SETPARAMS) 53136406Ssklower printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, 53236406Ssklower cmd==PRCO_GETOPT?"GET":"SET"); 53336406Ssklower ENDDEBUG 53436406Ssklower IFDEBUG(D_REQUEST) 53536406Ssklower printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, 53636406Ssklower cmd==PRCO_GETOPT?"GET":"SET"); 53736406Ssklower ENDDEBUG 53836406Ssklower 53936406Ssklower if ( cmd == PRCO_GETOPT ) { 54036406Ssklower *(struct tp_conn_param *)value = tpcb->_tp_param; 54136406Ssklower (*mp)->m_len = sizeof(tpcb->_tp_param); 54236406Ssklower } else /* cmd == PRCO_SETOPT */ { 54336406Ssklower if( (error = 54436406Ssklower tp_consistency(tpcb, TP_STRICT | TP_FORCE, 54536406Ssklower (struct tp_conn_param *)value))==0) { 54636406Ssklower /* 54736406Ssklower * tp_consistency doesn't copy the whole set of params 54836406Ssklower */ 54936406Ssklower tpcb->_tp_param = *(struct tp_conn_param *)value; 55036406Ssklower (*mp)->m_len = sizeof(tpcb->_tp_param); 55136406Ssklower } 55236406Ssklower } 55336406Ssklower break; 55436406Ssklower 55536406Ssklower case TPOPT_PSTATISTICS: 55636406Ssklower #ifdef TP_PERF_MEAS 55736406Ssklower if (cmd == PRCO_SETOPT) { 55836406Ssklower error = EINVAL; goto done; 55936406Ssklower } 56036406Ssklower IFPERF(tpcb) 56137469Ssklower if (*mp) { 56237469Ssklower struct mbuf * n; 56337469Ssklower do { 56437469Ssklower MFREE(*mp, n); 56537469Ssklower *mp = n; 56637469Ssklower } while (n); 56737469Ssklower } 56837469Ssklower *mp = m_copym(tpcb->tp_p_mbuf, (int)M_COPYALL, M_WAITOK); 56936406Ssklower ENDPERF 57036406Ssklower else { 57136406Ssklower error = EINVAL; goto done; 57236406Ssklower } 57336406Ssklower break; 57436406Ssklower #else 57536406Ssklower error = EOPNOTSUPP; 57636406Ssklower goto done; 57736406Ssklower #endif TP_PERF_MEAS 57836406Ssklower 57936406Ssklower case TPOPT_CDDATA_CLEAR: 58036406Ssklower if (cmd == PRCO_GETOPT) { 58136406Ssklower error = EINVAL; 58236406Ssklower } else { 58337469Ssklower if (tpcb->tp_ucddata) { 58438841Ssklower m_freem(tpcb->tp_ucddata); 58538841Ssklower tpcb->tp_ucddata = 0; 58636406Ssklower } 58736406Ssklower } 58836406Ssklower break; 58936406Ssklower 59038841Ssklower case TPOPT_CFRM_DATA: 59136406Ssklower case TPOPT_DISC_DATA: 59236406Ssklower case TPOPT_CONN_DATA: 59336406Ssklower if( tpcb->tp_class == TP_CLASS_0 ) { 59436406Ssklower error = EOPNOTSUPP; 59536406Ssklower break; 59636406Ssklower } 59736406Ssklower IFDEBUG(D_REQUEST) 59836406Ssklower printf("%s\n", optname==TPOPT_DISC_DATA?"DISC data":"CONN data"); 59936406Ssklower printf("m_len 0x%x, vallen 0x%x so_snd.cc 0x%x\n", 60036406Ssklower (*mp)->m_len, val_len, so->so_snd.sb_cc); 60136406Ssklower dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput: sosnd "); 60236406Ssklower ENDDEBUG 60336406Ssklower if (cmd == PRCO_SETOPT) { 60437469Ssklower int len = tpcb->tp_ucddata ? tpcb->tp_ucddata->m_len : 0; 60536406Ssklower /* can append connect data in several calls */ 60637469Ssklower if (len + val_len > 60736406Ssklower (optname==TPOPT_CONN_DATA?TP_MAX_CR_DATA:TP_MAX_DR_DATA) ) { 60836406Ssklower error = EMSGSIZE; goto done; 60936406Ssklower } 61036406Ssklower (*mp)->m_next = MNULL; 61136406Ssklower (*mp)->m_act = 0; 61237469Ssklower if (tpcb->tp_ucddata) 61337469Ssklower m_cat(tpcb->tp_ucddata, *mp); 61437469Ssklower else 61537469Ssklower tpcb->tp_ucddata = *mp; 61640241Ssklower IFDEBUG(D_REQUEST) 61740241Ssklower dump_mbuf(tpcb->tp_ucddata, "tp_ctloutput after CONN_DATA"); 61840241Ssklower ENDDEBUG 61936406Ssklower IFTRACE(D_REQUEST) 62036406Ssklower tptrace(TPPTmisc,"C/D DATA: flags snd.sbcc val_len", 62136406Ssklower tpcb->tp_flags, so->so_snd.sb_cc,val_len,0); 62236406Ssklower ENDTRACE 62336406Ssklower *mp = MNULL; /* prevent sosetopt from freeing it! */ 62440241Ssklower if (optname == TPOPT_CFRM_DATA && (so->so_state & SS_ISCONFIRMING)) 62540241Ssklower (void) tp_confirm(tpcb); 62636406Ssklower } 62736406Ssklower break; 62836406Ssklower 62936406Ssklower case TPOPT_PERF_MEAS: 63036406Ssklower #ifdef TP_PERF_MEAS 63136406Ssklower if (cmd == PRCO_GETOPT) { 63236406Ssklower *value = (u_int)tpcb->tp_perf_on; 63336406Ssklower (*mp)->m_len = sizeof(u_int); 63436406Ssklower } else if (cmd == PRCO_SETOPT) { 63536406Ssklower (*mp)->m_len = 0; 63636406Ssklower if ((*value) != 0 && (*value) != 1 ) 63736406Ssklower error = EINVAL; 63836406Ssklower else tpcb->tp_perf_on = (*value); 63936406Ssklower } 64036406Ssklower if( tpcb->tp_perf_on ) 64136406Ssklower error = tp_setup_perf(tpcb); 64236406Ssklower #else TP_PERF_MEAS 64336406Ssklower error = EOPNOTSUPP; 64436406Ssklower #endif TP_PERF_MEAS 64536406Ssklower break; 64636406Ssklower 64736406Ssklower default: 64836406Ssklower error = EOPNOTSUPP; 64936406Ssklower } 65036406Ssklower 65136406Ssklower done: 65236406Ssklower IFDEBUG(D_REQUEST) 65336406Ssklower dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput sosnd at end"); 65436406Ssklower dump_mbuf(*mp, "tp_ctloutput *mp"); 65536406Ssklower ENDDEBUG 65636406Ssklower /* 65736406Ssklower * sigh: getsockopt looks only at m_len : all output data must 65836406Ssklower * reside in the first mbuf 65936406Ssklower */ 66036406Ssklower if ( error && (*mp) != MNULL ) 66136406Ssklower (*mp)->m_len = 0; 66236406Ssklower if( (*mp) != MNULL ) { 66336406Ssklower ASSERT ( m_compress(*mp, mp) <= MLEN ); 66436406Ssklower IFDEBUG(D_REQUEST) 66536406Ssklower dump_mbuf(*mp, "tp_ctloutput *mp after compress"); 66636406Ssklower ENDDEBUG 66736406Ssklower } 66836406Ssklower 66936406Ssklower splx(s); 67036406Ssklower return error; 67136406Ssklower } 672