1*49268Sbostic /*- 2*49268Sbostic * Copyright (c) 1991 The Regents of the University of California. 3*49268Sbostic * All rights reserved. 4*49268Sbostic * 5*49268Sbostic * %sccs.include.redist.c% 6*49268Sbostic * 7*49268Sbostic * @(#)tp_output.c 7.9 (Berkeley) 05/06/91 8*49268Sbostic */ 9*49268Sbostic 1036406Ssklower /*********************************************************** 1136406Ssklower Copyright IBM Corporation 1987 1236406Ssklower 1336406Ssklower All Rights Reserved 1436406Ssklower 1536406Ssklower Permission to use, copy, modify, and distribute this software and its 1636406Ssklower documentation for any purpose and without fee is hereby granted, 1736406Ssklower provided that the above copyright notice appear in all copies and that 1836406Ssklower both that copyright notice and this permission notice appear in 1936406Ssklower supporting documentation, and that the name of IBM not be 2036406Ssklower used in advertising or publicity pertaining to distribution of the 2136406Ssklower software without specific, written prior permission. 2236406Ssklower 2336406Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 2436406Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 2536406Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 2636406Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 2736406Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 2836406Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2936406Ssklower SOFTWARE. 3036406Ssklower 3136406Ssklower ******************************************************************/ 3236406Ssklower 3336406Ssklower /* 3436406Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 3536406Ssklower */ 3636406Ssklower /* 3736406Ssklower * ARGO TP 3836406Ssklower * 3936406Ssklower * $Header: tp_output.c,v 5.4 88/11/18 17:28:08 nhall Exp $ 4036406Ssklower * $Source: /usr/argo/sys/netiso/RCS/tp_output.c,v $ 4136406Ssklower * 4236406Ssklower * In here is tp_ctloutput(), the guy called by [sg]etsockopt(), 4336406Ssklower */ 4436406Ssklower 4536406Ssklower #include "param.h" 4644424Ssklower #include "mbuf.h" 4736406Ssklower #include "systm.h" 4836406Ssklower #include "socket.h" 4936406Ssklower #include "socketvar.h" 5044424Ssklower #include "protosw.h" 5144424Ssklower #include "user.h" 5244424Ssklower #include "kernel.h" 5336406Ssklower #include "errno.h" 5436406Ssklower #include "time.h" 5537469Ssklower #include "tp_param.h" 5637469Ssklower #include "tp_user.h" 5737469Ssklower #include "tp_stat.h" 5837469Ssklower #include "tp_ip.h" 5944424Ssklower #include "tp_clnp.h" 6037469Ssklower #include "tp_timer.h" 6137469Ssklower #include "argo_debug.h" 6237469Ssklower #include "tp_pcb.h" 6337469Ssklower #include "tp_trace.h" 6436406Ssklower 6536406Ssklower #define USERFLAGSMASK_G 0x0f00643b 6636406Ssklower #define USERFLAGSMASK_S 0x0f000432 6736406Ssklower #define TPDUSIZESHIFT 24 6836406Ssklower #define CLASSHIFT 16 6936406Ssklower 7036406Ssklower /* 7136406Ssklower * NAME: tp_consistency() 7236406Ssklower * 7336406Ssklower * CALLED FROM: 7436406Ssklower * tp_ctloutput(), tp_input() 7536406Ssklower * 7636406Ssklower * FUNCTION and ARGUMENTS: 7736406Ssklower * Checks the consistency of options and tpdusize with class, 7836406Ssklower * using the parameters passed in via (param). 7936406Ssklower * (cmd) may be TP_STRICT or TP_FORCE or both. 8036406Ssklower * Force means it will set all the values in (tpcb) to those in 8136406Ssklower * the input arguements iff no errors were encountered. 8236406Ssklower * Strict means that no inconsistency will be tolerated. If it's 8336406Ssklower * not used, checksum and tpdusize inconsistencies will be tolerated. 8436406Ssklower * The reason for this is that in some cases, when we're negotiating down 8536406Ssklower * from class 4, these options should be changed but should not 8636406Ssklower * cause negotiation to fail. 8736406Ssklower * 8836406Ssklower * RETURNS 8936406Ssklower * E* or EOK 9036406Ssklower * E* if the various parms aren't ok for a given class 9136406Ssklower * EOK if they are ok for a given class 9236406Ssklower */ 9336406Ssklower 9436406Ssklower int 9536406Ssklower tp_consistency( tpcb, cmd, param ) 9636406Ssklower u_int cmd; 9736406Ssklower struct tp_conn_param *param; 9836406Ssklower struct tp_pcb *tpcb; 9936406Ssklower { 10036406Ssklower register int error = EOK; 10136406Ssklower int class_to_use = tp_mask_to_num(param->p_class); 10236406Ssklower 10336406Ssklower IFTRACE(D_SETPARAMS) 10436406Ssklower tptrace(TPPTmisc, 10536406Ssklower "tp_consist enter class_to_use dontchange param.class cmd", 10636406Ssklower class_to_use, param->p_dont_change_params, param->p_class, cmd); 10736406Ssklower ENDTRACE 10836406Ssklower IFDEBUG(D_SETPARAMS) 10936406Ssklower printf("tp_consistency %s %s\n", 11036406Ssklower cmd& TP_FORCE? "TP_FORCE": "", 11136406Ssklower cmd& TP_STRICT? "TP_STRICT":""); 11236406Ssklower ENDDEBUG 11336406Ssklower if ((cmd & TP_FORCE) && (param->p_dont_change_params)) { 11436406Ssklower cmd &= ~TP_FORCE; 11536406Ssklower } 11636406Ssklower /* can switch net services within a domain, but 11736406Ssklower * cannot switch domains 11836406Ssklower */ 11936406Ssklower switch( param->p_netservice) { 12036406Ssklower case ISO_CONS: 12136406Ssklower case ISO_CLNS: 12236406Ssklower case ISO_COSNS: 12336406Ssklower /* param->p_netservice in ISO DOMAIN */ 12436406Ssklower if(tpcb->tp_domain != AF_ISO ) { 12536406Ssklower error = EINVAL; goto done; 12636406Ssklower } 12736406Ssklower break; 12836406Ssklower case IN_CLNS: 12936406Ssklower /* param->p_netservice in INET DOMAIN */ 13036406Ssklower if( tpcb->tp_domain != AF_INET ) { 13136406Ssklower error = EINVAL; goto done; 13236406Ssklower } 13336406Ssklower break; 13436406Ssklower /* no others not possible-> netservice is a 2-bit field! */ 13536406Ssklower } 13636406Ssklower 13736406Ssklower IFDEBUG(D_SETPARAMS) 13836406Ssklower printf("p_class 0x%x, class_to_use 0x%x\n", param->p_class, 13936406Ssklower class_to_use); 14036406Ssklower ENDDEBUG 14136406Ssklower if((param->p_netservice < 0) || (param->p_netservice > TP_MAX_NETSERVICES)){ 14236406Ssklower error = EINVAL; goto done; 14336406Ssklower } 14436406Ssklower if( (param->p_class & TP_CLASSES_IMPLEMENTED) == 0 ) { 14536406Ssklower error = EINVAL; goto done; 14636406Ssklower } 14736406Ssklower IFDEBUG(D_SETPARAMS) 14836406Ssklower printf("Nretrans 0x%x\n", param->p_Nretrans ); 14936406Ssklower ENDDEBUG 15036406Ssklower if( ( param->p_Nretrans < 1 ) || 15136406Ssklower (param->p_cr_ticks < 1) || (param->p_cc_ticks < 1) ) { 15236406Ssklower /* bad for any class because negot has to be done a la class 4 */ 15336406Ssklower error = EINVAL; goto done; 15436406Ssklower } 15536406Ssklower IFDEBUG(D_SETPARAMS) 15636406Ssklower printf("winsize 0x%x\n", param->p_winsize ); 15736406Ssklower ENDDEBUG 15836406Ssklower if( (param->p_winsize < 128 ) || 15936406Ssklower (param->p_winsize < param->p_tpdusize ) || 16036406Ssklower (param->p_winsize > ((1+SB_MAX)>>2 /* 1/4 of the max */)) ) { 16136406Ssklower error = EINVAL; goto done; 16236406Ssklower } else { 16336406Ssklower if( tpcb->tp_state == TP_CLOSED ) 16437469Ssklower soreserve(tpcb->tp_sock, (u_long)param->p_winsize, 16537469Ssklower (u_long)param->p_winsize); 16636406Ssklower } 16736406Ssklower IFDEBUG(D_SETPARAMS) 16836406Ssklower printf("use_csum 0x%x\n", param->p_use_checksum ); 16936406Ssklower printf("xtd_format 0x%x\n", param->p_xtd_format ); 17036406Ssklower printf("xpd_service 0x%x\n", param->p_xpd_service ); 17136406Ssklower printf("tpdusize 0x%x\n", param->p_tpdusize ); 17236406Ssklower printf("tpcb->flags 0x%x\n", tpcb->tp_flags ); 17336406Ssklower ENDDEBUG 17436406Ssklower switch( class_to_use ) { 17536406Ssklower 17636406Ssklower case 0: 17736406Ssklower /* do not use checksums, xtd format, or XPD */ 17836406Ssklower 17936406Ssklower if( param->p_use_checksum | param->p_xtd_format | param->p_xpd_service ) { 18036406Ssklower if(cmd & TP_STRICT) { 18136406Ssklower error = EINVAL; 18236406Ssklower } else { 18336406Ssklower param->p_use_checksum = 0; 18436406Ssklower param->p_xtd_format = 0; 18536406Ssklower param->p_xpd_service = 0; 18636406Ssklower } 18736406Ssklower break; 18836406Ssklower } 18936406Ssklower 19036406Ssklower if (param->p_tpdusize < TP_MIN_TPDUSIZE) { 19136406Ssklower if(cmd & TP_STRICT) { 19236406Ssklower error = EINVAL; 19336406Ssklower } else { 19436406Ssklower param->p_tpdusize = TP_MIN_TPDUSIZE; 19536406Ssklower } 19636406Ssklower break; 19736406Ssklower } 19836406Ssklower if (param->p_tpdusize > TP0_TPDUSIZE) { 19936406Ssklower if (cmd & TP_STRICT) { 20036406Ssklower error = EINVAL; 20136406Ssklower } else { 20236406Ssklower param->p_tpdusize = TP0_TPDUSIZE; 20336406Ssklower } 20436406Ssklower break; 20536406Ssklower } 20636406Ssklower 20736406Ssklower /* connect/disc data not allowed for class 0 */ 20837469Ssklower if (tpcb->tp_ucddata) { 20936406Ssklower if(cmd & TP_STRICT) { 21036406Ssklower error = EINVAL; 21136406Ssklower } else if(cmd & TP_FORCE) { 21237469Ssklower m_freem(tpcb->tp_ucddata); 21337469Ssklower tpcb->tp_ucddata = 0; 21436406Ssklower } 21536406Ssklower } 21636406Ssklower break; 21736406Ssklower 21836406Ssklower case 4: 21936406Ssklower IFDEBUG(D_SETPARAMS) 22036406Ssklower printf("dt_ticks 0x%x\n", param->p_dt_ticks ); 22136406Ssklower printf("x_ticks 0x%x\n", param->p_x_ticks ); 22236406Ssklower printf("dr_ticks 0x%x\n", param->p_dr_ticks ); 22336406Ssklower printf("keepalive 0x%x\n", param->p_keepalive_ticks ); 22436406Ssklower printf("sendack 0x%x\n", param->p_sendack_ticks ); 22536406Ssklower printf("inact 0x%x\n", param->p_inact_ticks ); 22636406Ssklower printf("ref 0x%x\n", param->p_ref_ticks ); 22736406Ssklower ENDDEBUG 22836406Ssklower if( (param->p_class & TP_CLASS_4 ) && ( 22936406Ssklower (param->p_dt_ticks < 1) || (param->p_dr_ticks < 1) || 23036406Ssklower (param->p_x_ticks < 1) || (param->p_keepalive_ticks < 1) || 23136406Ssklower (param->p_sendack_ticks < 1) || (param->p_ref_ticks < 1) || 23236406Ssklower (param->p_inact_ticks < 1) ) ) { 23336406Ssklower error = EINVAL; 23436406Ssklower break; 23536406Ssklower } 23636406Ssklower IFDEBUG(D_SETPARAMS) 23736406Ssklower printf("rx_strat 0x%x\n", param->p_rx_strat ); 23836406Ssklower ENDDEBUG 23936406Ssklower if(param->p_rx_strat > 24036406Ssklower ( TPRX_USE_CW | TPRX_EACH | TPRX_FASTSTART) ) { 24136406Ssklower if(cmd & TP_STRICT) { 24236406Ssklower error = EINVAL; 24336406Ssklower } else { 24436406Ssklower param->p_rx_strat = TPRX_USE_CW; 24536406Ssklower } 24636406Ssklower break; 24736406Ssklower } 24836406Ssklower IFDEBUG(D_SETPARAMS) 24936406Ssklower printf("ack_strat 0x%x\n", param->p_ack_strat ); 25036406Ssklower ENDDEBUG 25136406Ssklower if((param->p_ack_strat != 0) && (param->p_ack_strat != 1)) { 25236406Ssklower if(cmd & TP_STRICT) { 25336406Ssklower error = EINVAL; 25436406Ssklower } else { 25536406Ssklower param->p_ack_strat = TPACK_WINDOW; 25636406Ssklower } 25736406Ssklower break; 25836406Ssklower } 25936406Ssklower if (param->p_tpdusize < TP_MIN_TPDUSIZE) { 26036406Ssklower if(cmd & TP_STRICT) { 26136406Ssklower error = EINVAL; 26236406Ssklower } else { 26336406Ssklower param->p_tpdusize = TP_MIN_TPDUSIZE; 26436406Ssklower } 26536406Ssklower break; 26636406Ssklower } 26736406Ssklower if (param->p_tpdusize > TP_TPDUSIZE) { 26836406Ssklower if(cmd & TP_STRICT) { 26936406Ssklower error = EINVAL; 27036406Ssklower } else { 27136406Ssklower param->p_tpdusize = TP_TPDUSIZE; 27236406Ssklower } 27336406Ssklower break; 27436406Ssklower } 27536406Ssklower break; 27636406Ssklower } 27736406Ssklower 27836406Ssklower if ((error==0) && (cmd & TP_FORCE)) { 27947282Ssklower /* Enforce Negotation rules below */ 28047282Ssklower if (tpcb->tp_tpdusize > param->p_tpdusize) 28147282Ssklower tpcb->tp_tpdusize = param->p_tpdusize; 28236406Ssklower tpcb->tp_class = param->p_class; 28347282Ssklower if (tpcb->tp_use_checksum || param->p_use_checksum) 28447282Ssklower tpcb->tp_use_checksum = 1; 28547282Ssklower if (!tpcb->tp_xpd_service || !param->p_xpd_service) 28647282Ssklower tpcb->tp_xpd_service = 0; 28747282Ssklower if (!tpcb->tp_xtd_format || !param->p_xtd_format) 28847282Ssklower tpcb->tp_xtd_format = 0; 28936406Ssklower } 29036406Ssklower 29136406Ssklower done: 29236406Ssklower 29336406Ssklower IFTRACE(D_CONN) 29436406Ssklower tptrace(TPPTmisc, "tp_consist returns class xtdfmt cmd", 29536406Ssklower error, tpcb->tp_class, tpcb->tp_xtd_format, cmd); 29636406Ssklower ENDTRACE 29736406Ssklower IFDEBUG(D_CONN) 29836406Ssklower printf( 29936406Ssklower "tp_consist rtns 0x%x class 0x%x xtd_fmt 0x%x cmd 0x%x\n", 30036406Ssklower error, tpcb->tp_class, tpcb->tp_xtd_format, cmd); 30136406Ssklower ENDDEBUG 30236406Ssklower return error; 30336406Ssklower } 30436406Ssklower 30536406Ssklower /* 30636406Ssklower * NAME: tp_ctloutput() 30736406Ssklower * 30836406Ssklower * CALLED FROM: 30936406Ssklower * [sg]etsockopt(), via so[sg]etopt(). 31036406Ssklower * 31136406Ssklower * FUNCTION and ARGUMENTS: 31236406Ssklower * Implements the socket options at transport level. 31337536Smckusick * (cmd) is either PRCO_SETOPT or PRCO_GETOPT (see ../sys/protosw.h). 31436406Ssklower * (so) is the socket. 31537536Smckusick * (level) is SOL_TRANSPORT (see ../sys/socket.h) 31636406Ssklower * (optname) is the particular command or option to be set. 31736406Ssklower * (**mp) is an mbuf structure. 31836406Ssklower * 31936406Ssklower * RETURN VALUE: 32036406Ssklower * ENOTSOCK if the socket hasn't got an associated tpcb 32136406Ssklower * EINVAL if 32236406Ssklower * trying to set window too big 32336406Ssklower * trying to set illegal max tpdu size 32436406Ssklower * trying to set illegal credit fraction 32536406Ssklower * trying to use unknown or unimplemented class of TP 32636406Ssklower * structure passed to set timer values is wrong size 32736406Ssklower * illegal combination of command/GET-SET option, 32836406Ssklower * e.g., GET w/ TPOPT_CDDATA_CLEAR: 32936406Ssklower * EOPNOTSUPP if the level isn't transport, or command is neither GET nor SET 33036406Ssklower * or if the transport-specific command is not implemented 33136406Ssklower * EISCONN if trying a command that isn't allowed after a connection 33236406Ssklower * is established 33336406Ssklower * ENOTCONN if trying a command that is allowed only if a connection is 33436406Ssklower * established 33536406Ssklower * EMSGSIZE if trying to give too much data on connect/disconnect 33636406Ssklower * 33736406Ssklower * SIDE EFFECTS: 33836406Ssklower * 33936406Ssklower * NOTES: 34036406Ssklower */ 34136406Ssklower ProtoHook 34236406Ssklower tp_ctloutput(cmd, so, level, optname, mp) 34336406Ssklower int cmd, level, optname; 34436406Ssklower struct socket *so; 34536406Ssklower struct mbuf **mp; 34636406Ssklower { 34736406Ssklower struct tp_pcb *tpcb = sototpcb(so); 34836406Ssklower int s = splnet(); 34937469Ssklower caddr_t value; 35037469Ssklower unsigned val_len; 35136406Ssklower int error = 0; 35236406Ssklower 35336406Ssklower IFTRACE(D_REQUEST) 35436406Ssklower tptrace(TPPTmisc, "tp_ctloutput cmd so optname mp", 35536406Ssklower cmd, so, optname, mp); 35636406Ssklower ENDTRACE 35736406Ssklower IFDEBUG(D_REQUEST) 35836406Ssklower printf( 35936406Ssklower "tp_ctloutput so 0x%x cmd 0x%x optname 0x%x, mp 0x%x *mp 0x%x tpcb 0x%x\n", 36036406Ssklower so, cmd, optname, mp, mp?*mp:0, tpcb); 36136406Ssklower ENDDEBUG 36236406Ssklower if( tpcb == (struct tp_pcb *)0 ) { 36336406Ssklower error = ENOTSOCK; goto done; 36436406Ssklower } 36536406Ssklower if(*mp == MNULL) { 36636406Ssklower register struct mbuf *m; 36736406Ssklower 36836406Ssklower MGET(m, M_DONTWAIT, TPMT_SONAME); /* does off, type, next */ 36936406Ssklower if (m == NULL) { 37036406Ssklower splx(s); 37136406Ssklower return ENOBUFS; 37236406Ssklower } 37336406Ssklower m->m_len = 0; 37436406Ssklower m->m_act = 0; 37536406Ssklower *mp = m; 37636406Ssklower } 37736406Ssklower 37836406Ssklower /* 37936406Ssklower * Hook so one can set network options via a tp socket. 38036406Ssklower */ 38136406Ssklower if ( level == SOL_NETWORK ) { 38236406Ssklower if ((tpcb->tp_nlproto == NULL) || (tpcb->tp_npcb == NULL)) 38336406Ssklower error = ENOTSOCK; 38436406Ssklower else if (tpcb->tp_nlproto->nlp_ctloutput == NULL) 38536406Ssklower error = EOPNOTSUPP; 38636406Ssklower else 38736406Ssklower error = (tpcb->tp_nlproto->nlp_ctloutput)(cmd, optname, 38836406Ssklower tpcb->tp_npcb, *mp); 38936406Ssklower goto done; 39036406Ssklower } else if ( level != SOL_TRANSPORT ) { 39136406Ssklower error = EOPNOTSUPP; goto done; 39236406Ssklower } 39336406Ssklower if (cmd != PRCO_GETOPT && cmd != PRCO_SETOPT) { 39436406Ssklower error = EOPNOTSUPP; goto done; 39536406Ssklower } 39636406Ssklower if ( so->so_error ) { 39736406Ssklower error = so->so_error; goto done; 39836406Ssklower } 39936406Ssklower 40036406Ssklower /* The only options allowed after connection is established 40136406Ssklower * are GET (anything) and SET DISC DATA and SET PERF MEAS 40236406Ssklower */ 40336406Ssklower if ( ((so->so_state & SS_ISCONNECTING)||(so->so_state & SS_ISCONNECTED)) 40436406Ssklower && 40536406Ssklower (cmd == PRCO_SETOPT && 40636406Ssklower optname != TPOPT_DISC_DATA && 40738841Ssklower optname != TPOPT_CFRM_DATA && 40836406Ssklower optname != TPOPT_PERF_MEAS && 40936406Ssklower optname != TPOPT_CDDATA_CLEAR ) ) { 41036406Ssklower error = EISCONN; goto done; 41136406Ssklower } 41236406Ssklower /* The only options allowed after disconnection are GET DISC DATA, 41336406Ssklower * and TPOPT_PSTATISTICS 41436406Ssklower * and they're not allowed if the ref timer has gone off, because 41536406Ssklower * the tpcb is gone 41636406Ssklower */ 41738841Ssklower if ((so->so_state & (SS_ISCONNECTED | SS_ISCONFIRMING)) == 0) { 41836406Ssklower if ( so->so_tpcb == (caddr_t)0 ) { 41936406Ssklower error = ENOTCONN; goto done; 42036406Ssklower } 42136406Ssklower if ( (tpcb->tp_state == TP_REFWAIT || tpcb->tp_state == TP_CLOSING) && 42236406Ssklower (optname != TPOPT_DISC_DATA && optname != TPOPT_PSTATISTICS)) { 42336406Ssklower error = ENOTCONN; goto done; 42436406Ssklower } 42536406Ssklower } 42636406Ssklower 42737469Ssklower value = mtod(*mp, caddr_t); /* it's aligned, don't worry, 42837469Ssklower * but lint complains about it 42937469Ssklower */ 43036406Ssklower val_len = (*mp)->m_len; 43136406Ssklower 43236406Ssklower switch (optname) { 43336406Ssklower 43444424Ssklower case TPOPT_INTERCEPT: 43544424Ssklower if (error = suser(u.u_cred, &u.u_acflag)) 43644424Ssklower break; 43744424Ssklower else if (cmd != PRCO_SETOPT || tpcb->tp_state != TP_LISTENING) 43844424Ssklower error = EINVAL; 43944424Ssklower else { 44044424Ssklower register struct tp_pcb *t = 0; 44144424Ssklower struct mbuf *m = m_getclr(M_WAIT, MT_SONAME); 44244424Ssklower struct sockaddr *sa = mtod(m, struct sockaddr *); 44344424Ssklower (*tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, m, TP_LOCAL); 44444424Ssklower switch (sa->sa_family) { 44544424Ssklower case AF_ISO: 44644424Ssklower if (((struct sockaddr_iso *)sa)->siso_nlen == 0) 44744424Ssklower default: error = EINVAL; 44844424Ssklower break; 44944424Ssklower case AF_INET: 45044424Ssklower if (((struct sockaddr_in *)sa)->sin_addr.s_addr == 0) 45144424Ssklower error = EINVAL; 45244424Ssklower break; 45344424Ssklower } 45444424Ssklower for (t = tp_intercepts; t; t = t->tp_nextlisten) { 45544424Ssklower if (t->tp_nlproto->nlp_afamily != tpcb->tp_nlproto->nlp_afamily) 45644424Ssklower continue; 45744424Ssklower if ((*t->tp_nlproto->nlp_cmpnetaddr)(t->tp_npcb, sa, TP_LOCAL)) 45844424Ssklower error = EADDRINUSE; 45944424Ssklower } 46044424Ssklower m_freem(m); 46144424Ssklower if (error) 46244424Ssklower break; 46344424Ssklower } 46444424Ssklower { 46544424Ssklower register struct tp_pcb **tt; 46644424Ssklower for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten)) 46744424Ssklower if (*tt == tpcb) 46844424Ssklower break; 46944424Ssklower if (*tt) 47044424Ssklower *tt = tpcb->tp_nextlisten; 47144424Ssklower else 47244424Ssklower {error = EHOSTUNREACH; goto done; } 47344424Ssklower } 47444601Ssklower tpcb->tp_nextlisten = tp_intercepts; 47544424Ssklower tp_intercepts = tpcb; 47644424Ssklower break; 47744424Ssklower 47836406Ssklower case TPOPT_MY_TSEL: 47936406Ssklower if ( cmd == PRCO_GETOPT ) { 48036406Ssklower ASSERT( tpcb->tp_lsuffixlen <= MAX_TSAP_SEL_LEN ); 48137469Ssklower bcopy((caddr_t)tpcb->tp_lsuffix, value, tpcb->tp_lsuffixlen); 48236406Ssklower (*mp)->m_len = tpcb->tp_lsuffixlen; 48336406Ssklower } else /* cmd == PRCO_SETOPT */ { 48436406Ssklower if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { 48536406Ssklower printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); 48636406Ssklower error = EINVAL; 48736406Ssklower } else { 48837469Ssklower bcopy(value, (caddr_t)tpcb->tp_lsuffix, val_len); 48936406Ssklower tpcb->tp_lsuffixlen = val_len; 49036406Ssklower } 49136406Ssklower } 49236406Ssklower break; 49336406Ssklower 49436406Ssklower case TPOPT_PEER_TSEL: 49536406Ssklower if ( cmd == PRCO_GETOPT ) { 49636406Ssklower ASSERT( tpcb->tp_fsuffixlen <= MAX_TSAP_SEL_LEN ); 49737469Ssklower bcopy((caddr_t)tpcb->tp_fsuffix, value, tpcb->tp_fsuffixlen); 49836406Ssklower (*mp)->m_len = tpcb->tp_fsuffixlen; 49936406Ssklower } else /* cmd == PRCO_SETOPT */ { 50036406Ssklower if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { 50136406Ssklower printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); 50236406Ssklower error = EINVAL; 50336406Ssklower } else { 50437469Ssklower bcopy(value, (caddr_t)tpcb->tp_fsuffix, val_len); 50536406Ssklower tpcb->tp_fsuffixlen = val_len; 50636406Ssklower } 50736406Ssklower } 50836406Ssklower break; 50936406Ssklower 51036406Ssklower case TPOPT_FLAGS: 51136406Ssklower IFDEBUG(D_REQUEST) 51236406Ssklower printf("%s TPOPT_FLAGS value 0x%x *value 0x%x, flags 0x%x \n", 51336406Ssklower cmd==PRCO_GETOPT?"GET":"SET", 51436406Ssklower value, 51536406Ssklower *value, 51636406Ssklower tpcb->tp_flags); 51736406Ssklower ENDDEBUG 51836406Ssklower 51936406Ssklower if ( cmd == PRCO_GETOPT ) { 52036406Ssklower *(int *)value = (int)tpcb->tp_flags; 52136406Ssklower (*mp)->m_len = sizeof(u_int); 52236406Ssklower } else /* cmd == PRCO_SETOPT */ { 52336406Ssklower error = EINVAL; goto done; 52436406Ssklower } 52536406Ssklower break; 52636406Ssklower 52736406Ssklower case TPOPT_PARAMS: 52836406Ssklower /* This handles: 52936406Ssklower * timer values, 53036406Ssklower * class, use of transport expedited data, 53136406Ssklower * max tpdu size, checksum, xtd format and 53236406Ssklower * disconnect indications, and may get rid of connect/disc data 53336406Ssklower */ 53436406Ssklower IFDEBUG(D_SETPARAMS) 53536406Ssklower printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, 53636406Ssklower cmd==PRCO_GETOPT?"GET":"SET"); 53736406Ssklower ENDDEBUG 53836406Ssklower IFDEBUG(D_REQUEST) 53936406Ssklower printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, 54036406Ssklower cmd==PRCO_GETOPT?"GET":"SET"); 54136406Ssklower ENDDEBUG 54236406Ssklower 54336406Ssklower if ( cmd == PRCO_GETOPT ) { 54436406Ssklower *(struct tp_conn_param *)value = tpcb->_tp_param; 54536406Ssklower (*mp)->m_len = sizeof(tpcb->_tp_param); 54636406Ssklower } else /* cmd == PRCO_SETOPT */ { 54736406Ssklower if( (error = 54836406Ssklower tp_consistency(tpcb, TP_STRICT | TP_FORCE, 54936406Ssklower (struct tp_conn_param *)value))==0) { 55036406Ssklower /* 55136406Ssklower * tp_consistency doesn't copy the whole set of params 55236406Ssklower */ 55336406Ssklower tpcb->_tp_param = *(struct tp_conn_param *)value; 55436406Ssklower (*mp)->m_len = sizeof(tpcb->_tp_param); 55536406Ssklower } 55636406Ssklower } 55736406Ssklower break; 55836406Ssklower 55936406Ssklower case TPOPT_PSTATISTICS: 56036406Ssklower #ifdef TP_PERF_MEAS 56136406Ssklower if (cmd == PRCO_SETOPT) { 56236406Ssklower error = EINVAL; goto done; 56336406Ssklower } 56436406Ssklower IFPERF(tpcb) 56537469Ssklower if (*mp) { 56637469Ssklower struct mbuf * n; 56737469Ssklower do { 56837469Ssklower MFREE(*mp, n); 56937469Ssklower *mp = n; 57037469Ssklower } while (n); 57137469Ssklower } 57237469Ssklower *mp = m_copym(tpcb->tp_p_mbuf, (int)M_COPYALL, M_WAITOK); 57336406Ssklower ENDPERF 57436406Ssklower else { 57536406Ssklower error = EINVAL; goto done; 57636406Ssklower } 57736406Ssklower break; 57836406Ssklower #else 57936406Ssklower error = EOPNOTSUPP; 58036406Ssklower goto done; 58136406Ssklower #endif TP_PERF_MEAS 58236406Ssklower 58336406Ssklower case TPOPT_CDDATA_CLEAR: 58436406Ssklower if (cmd == PRCO_GETOPT) { 58536406Ssklower error = EINVAL; 58636406Ssklower } else { 58737469Ssklower if (tpcb->tp_ucddata) { 58838841Ssklower m_freem(tpcb->tp_ucddata); 58938841Ssklower tpcb->tp_ucddata = 0; 59036406Ssklower } 59136406Ssklower } 59236406Ssklower break; 59336406Ssklower 59438841Ssklower case TPOPT_CFRM_DATA: 59536406Ssklower case TPOPT_DISC_DATA: 59636406Ssklower case TPOPT_CONN_DATA: 59736406Ssklower if( tpcb->tp_class == TP_CLASS_0 ) { 59836406Ssklower error = EOPNOTSUPP; 59936406Ssklower break; 60036406Ssklower } 60136406Ssklower IFDEBUG(D_REQUEST) 60236406Ssklower printf("%s\n", optname==TPOPT_DISC_DATA?"DISC data":"CONN data"); 60336406Ssklower printf("m_len 0x%x, vallen 0x%x so_snd.cc 0x%x\n", 60436406Ssklower (*mp)->m_len, val_len, so->so_snd.sb_cc); 60536406Ssklower dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput: sosnd "); 60636406Ssklower ENDDEBUG 60736406Ssklower if (cmd == PRCO_SETOPT) { 60837469Ssklower int len = tpcb->tp_ucddata ? tpcb->tp_ucddata->m_len : 0; 60936406Ssklower /* can append connect data in several calls */ 61037469Ssklower if (len + val_len > 61136406Ssklower (optname==TPOPT_CONN_DATA?TP_MAX_CR_DATA:TP_MAX_DR_DATA) ) { 61236406Ssklower error = EMSGSIZE; goto done; 61336406Ssklower } 61436406Ssklower (*mp)->m_next = MNULL; 61536406Ssklower (*mp)->m_act = 0; 61637469Ssklower if (tpcb->tp_ucddata) 61737469Ssklower m_cat(tpcb->tp_ucddata, *mp); 61837469Ssklower else 61937469Ssklower tpcb->tp_ucddata = *mp; 62040241Ssklower IFDEBUG(D_REQUEST) 62140241Ssklower dump_mbuf(tpcb->tp_ucddata, "tp_ctloutput after CONN_DATA"); 62240241Ssklower ENDDEBUG 62336406Ssklower IFTRACE(D_REQUEST) 62436406Ssklower tptrace(TPPTmisc,"C/D DATA: flags snd.sbcc val_len", 62536406Ssklower tpcb->tp_flags, so->so_snd.sb_cc,val_len,0); 62636406Ssklower ENDTRACE 62736406Ssklower *mp = MNULL; /* prevent sosetopt from freeing it! */ 62840241Ssklower if (optname == TPOPT_CFRM_DATA && (so->so_state & SS_ISCONFIRMING)) 62940241Ssklower (void) tp_confirm(tpcb); 63036406Ssklower } 63136406Ssklower break; 63236406Ssklower 63336406Ssklower case TPOPT_PERF_MEAS: 63436406Ssklower #ifdef TP_PERF_MEAS 63536406Ssklower if (cmd == PRCO_GETOPT) { 63636406Ssklower *value = (u_int)tpcb->tp_perf_on; 63736406Ssklower (*mp)->m_len = sizeof(u_int); 63836406Ssklower } else if (cmd == PRCO_SETOPT) { 63936406Ssklower (*mp)->m_len = 0; 64036406Ssklower if ((*value) != 0 && (*value) != 1 ) 64136406Ssklower error = EINVAL; 64236406Ssklower else tpcb->tp_perf_on = (*value); 64336406Ssklower } 64436406Ssklower if( tpcb->tp_perf_on ) 64536406Ssklower error = tp_setup_perf(tpcb); 64636406Ssklower #else TP_PERF_MEAS 64736406Ssklower error = EOPNOTSUPP; 64836406Ssklower #endif TP_PERF_MEAS 64936406Ssklower break; 65036406Ssklower 65136406Ssklower default: 65236406Ssklower error = EOPNOTSUPP; 65336406Ssklower } 65436406Ssklower 65536406Ssklower done: 65636406Ssklower IFDEBUG(D_REQUEST) 65736406Ssklower dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput sosnd at end"); 65836406Ssklower dump_mbuf(*mp, "tp_ctloutput *mp"); 65936406Ssklower ENDDEBUG 66036406Ssklower /* 66136406Ssklower * sigh: getsockopt looks only at m_len : all output data must 66236406Ssklower * reside in the first mbuf 66336406Ssklower */ 66436406Ssklower if ( error && (*mp) != MNULL ) 66536406Ssklower (*mp)->m_len = 0; 66636406Ssklower if( (*mp) != MNULL ) { 66736406Ssklower ASSERT ( m_compress(*mp, mp) <= MLEN ); 66836406Ssklower IFDEBUG(D_REQUEST) 66936406Ssklower dump_mbuf(*mp, "tp_ctloutput *mp after compress"); 67036406Ssklower ENDDEBUG 67136406Ssklower } 67236406Ssklower 67336406Ssklower splx(s); 67436406Ssklower return error; 67536406Ssklower } 676