149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*56533Sbostic * @(#)tp_output.c 7.17 (Berkeley) 10/11/92 849268Sbostic */ 949268Sbostic 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 45*56533Sbostic #include <sys/param.h> 46*56533Sbostic #include <sys/mbuf.h> 47*56533Sbostic #include <sys/systm.h> 48*56533Sbostic #include <sys/socket.h> 49*56533Sbostic #include <sys/socketvar.h> 50*56533Sbostic #include <sys/protosw.h> 51*56533Sbostic #include <sys/errno.h> 52*56533Sbostic #include <sys/time.h> 53*56533Sbostic #include <sys/kernel.h> 5436406Ssklower 55*56533Sbostic #include <netiso/tp_param.h> 56*56533Sbostic #include <netiso/tp_user.h> 57*56533Sbostic #include <netiso/tp_stat.h> 58*56533Sbostic #include <netiso/tp_ip.h> 59*56533Sbostic #include <netiso/tp_clnp.h> 60*56533Sbostic #include <netiso/tp_timer.h> 61*56533Sbostic #include <netiso/argo_debug.h> 62*56533Sbostic #include <netiso/tp_pcb.h> 63*56533Sbostic #include <netiso/tp_trace.h> 64*56533Sbostic 6536406Ssklower #define TPDUSIZESHIFT 24 6636406Ssklower #define CLASSHIFT 16 6736406Ssklower 6836406Ssklower /* 6936406Ssklower * NAME: tp_consistency() 7036406Ssklower * 7136406Ssklower * CALLED FROM: 7236406Ssklower * tp_ctloutput(), tp_input() 7336406Ssklower * 7436406Ssklower * FUNCTION and ARGUMENTS: 7536406Ssklower * Checks the consistency of options and tpdusize with class, 7636406Ssklower * using the parameters passed in via (param). 7736406Ssklower * (cmd) may be TP_STRICT or TP_FORCE or both. 7836406Ssklower * Force means it will set all the values in (tpcb) to those in 7936406Ssklower * the input arguements iff no errors were encountered. 8036406Ssklower * Strict means that no inconsistency will be tolerated. If it's 8136406Ssklower * not used, checksum and tpdusize inconsistencies will be tolerated. 8236406Ssklower * The reason for this is that in some cases, when we're negotiating down 8336406Ssklower * from class 4, these options should be changed but should not 8436406Ssklower * cause negotiation to fail. 8536406Ssklower * 8636406Ssklower * RETURNS 8736406Ssklower * E* or EOK 8836406Ssklower * E* if the various parms aren't ok for a given class 8936406Ssklower * EOK if they are ok for a given class 9036406Ssklower */ 9136406Ssklower 9236406Ssklower int 9336406Ssklower tp_consistency( tpcb, cmd, param ) 9436406Ssklower u_int cmd; 9536406Ssklower struct tp_conn_param *param; 9636406Ssklower struct tp_pcb *tpcb; 9736406Ssklower { 9836406Ssklower register int error = EOK; 9936406Ssklower int class_to_use = tp_mask_to_num(param->p_class); 10036406Ssklower 10136406Ssklower IFTRACE(D_SETPARAMS) 10236406Ssklower tptrace(TPPTmisc, 10336406Ssklower "tp_consist enter class_to_use dontchange param.class cmd", 10436406Ssklower class_to_use, param->p_dont_change_params, param->p_class, cmd); 10536406Ssklower ENDTRACE 10636406Ssklower IFDEBUG(D_SETPARAMS) 10736406Ssklower printf("tp_consistency %s %s\n", 10836406Ssklower cmd& TP_FORCE? "TP_FORCE": "", 10936406Ssklower cmd& TP_STRICT? "TP_STRICT":""); 11036406Ssklower ENDDEBUG 11136406Ssklower if ((cmd & TP_FORCE) && (param->p_dont_change_params)) { 11236406Ssklower cmd &= ~TP_FORCE; 11336406Ssklower } 11436406Ssklower /* can switch net services within a domain, but 11536406Ssklower * cannot switch domains 11636406Ssklower */ 11736406Ssklower switch( param->p_netservice) { 11836406Ssklower case ISO_CONS: 11936406Ssklower case ISO_CLNS: 12036406Ssklower case ISO_COSNS: 12136406Ssklower /* param->p_netservice in ISO DOMAIN */ 12236406Ssklower if(tpcb->tp_domain != AF_ISO ) { 12336406Ssklower error = EINVAL; goto done; 12436406Ssklower } 12536406Ssklower break; 12636406Ssklower case IN_CLNS: 12736406Ssklower /* param->p_netservice in INET DOMAIN */ 12836406Ssklower if( tpcb->tp_domain != AF_INET ) { 12936406Ssklower error = EINVAL; goto done; 13036406Ssklower } 13136406Ssklower break; 13236406Ssklower /* no others not possible-> netservice is a 2-bit field! */ 13336406Ssklower } 13436406Ssklower 13536406Ssklower IFDEBUG(D_SETPARAMS) 13636406Ssklower printf("p_class 0x%x, class_to_use 0x%x\n", param->p_class, 13736406Ssklower class_to_use); 13836406Ssklower ENDDEBUG 13936406Ssklower if((param->p_netservice < 0) || (param->p_netservice > TP_MAX_NETSERVICES)){ 14036406Ssklower error = EINVAL; goto done; 14136406Ssklower } 14236406Ssklower if( (param->p_class & TP_CLASSES_IMPLEMENTED) == 0 ) { 14336406Ssklower error = EINVAL; goto done; 14436406Ssklower } 14536406Ssklower IFDEBUG(D_SETPARAMS) 14636406Ssklower printf("Nretrans 0x%x\n", param->p_Nretrans ); 14736406Ssklower ENDDEBUG 14836406Ssklower if( ( param->p_Nretrans < 1 ) || 14936406Ssklower (param->p_cr_ticks < 1) || (param->p_cc_ticks < 1) ) { 15036406Ssklower /* bad for any class because negot has to be done a la class 4 */ 15136406Ssklower error = EINVAL; goto done; 15236406Ssklower } 15336406Ssklower IFDEBUG(D_SETPARAMS) 15436406Ssklower printf("use_csum 0x%x\n", param->p_use_checksum ); 15536406Ssklower printf("xtd_format 0x%x\n", param->p_xtd_format ); 15636406Ssklower printf("xpd_service 0x%x\n", param->p_xpd_service ); 15736406Ssklower printf("tpdusize 0x%x\n", param->p_tpdusize ); 15836406Ssklower printf("tpcb->flags 0x%x\n", tpcb->tp_flags ); 15936406Ssklower ENDDEBUG 16036406Ssklower switch( class_to_use ) { 16136406Ssklower 16236406Ssklower case 0: 16336406Ssklower /* do not use checksums, xtd format, or XPD */ 16436406Ssklower 16536406Ssklower if( param->p_use_checksum | param->p_xtd_format | param->p_xpd_service ) { 16636406Ssklower if(cmd & TP_STRICT) { 16736406Ssklower error = EINVAL; 16836406Ssklower } else { 16936406Ssklower param->p_use_checksum = 0; 17036406Ssklower param->p_xtd_format = 0; 17136406Ssklower param->p_xpd_service = 0; 17236406Ssklower } 17336406Ssklower break; 17436406Ssklower } 17536406Ssklower 17636406Ssklower if (param->p_tpdusize < TP_MIN_TPDUSIZE) { 17736406Ssklower if(cmd & TP_STRICT) { 17836406Ssklower error = EINVAL; 17936406Ssklower } else { 18036406Ssklower param->p_tpdusize = TP_MIN_TPDUSIZE; 18136406Ssklower } 18236406Ssklower break; 18336406Ssklower } 18436406Ssklower if (param->p_tpdusize > TP0_TPDUSIZE) { 18536406Ssklower if (cmd & TP_STRICT) { 18636406Ssklower error = EINVAL; 18736406Ssklower } else { 18836406Ssklower param->p_tpdusize = TP0_TPDUSIZE; 18936406Ssklower } 19036406Ssklower break; 19136406Ssklower } 19236406Ssklower 19336406Ssklower /* connect/disc data not allowed for class 0 */ 19437469Ssklower if (tpcb->tp_ucddata) { 19536406Ssklower if(cmd & TP_STRICT) { 19636406Ssklower error = EINVAL; 19736406Ssklower } else if(cmd & TP_FORCE) { 19837469Ssklower m_freem(tpcb->tp_ucddata); 19937469Ssklower tpcb->tp_ucddata = 0; 20036406Ssklower } 20136406Ssklower } 20236406Ssklower break; 20336406Ssklower 20436406Ssklower case 4: 20536406Ssklower IFDEBUG(D_SETPARAMS) 20636406Ssklower printf("dt_ticks 0x%x\n", param->p_dt_ticks ); 20736406Ssklower printf("x_ticks 0x%x\n", param->p_x_ticks ); 20836406Ssklower printf("dr_ticks 0x%x\n", param->p_dr_ticks ); 20936406Ssklower printf("keepalive 0x%x\n", param->p_keepalive_ticks ); 21036406Ssklower printf("sendack 0x%x\n", param->p_sendack_ticks ); 21136406Ssklower printf("inact 0x%x\n", param->p_inact_ticks ); 21236406Ssklower printf("ref 0x%x\n", param->p_ref_ticks ); 21336406Ssklower ENDDEBUG 21436406Ssklower if( (param->p_class & TP_CLASS_4 ) && ( 21536406Ssklower (param->p_dt_ticks < 1) || (param->p_dr_ticks < 1) || 21636406Ssklower (param->p_x_ticks < 1) || (param->p_keepalive_ticks < 1) || 21736406Ssklower (param->p_sendack_ticks < 1) || (param->p_ref_ticks < 1) || 21836406Ssklower (param->p_inact_ticks < 1) ) ) { 21936406Ssklower error = EINVAL; 22036406Ssklower break; 22136406Ssklower } 22236406Ssklower IFDEBUG(D_SETPARAMS) 22336406Ssklower printf("rx_strat 0x%x\n", param->p_rx_strat ); 22436406Ssklower ENDDEBUG 22536406Ssklower if(param->p_rx_strat > 22636406Ssklower ( TPRX_USE_CW | TPRX_EACH | TPRX_FASTSTART) ) { 22736406Ssklower if(cmd & TP_STRICT) { 22836406Ssklower error = EINVAL; 22936406Ssklower } else { 23036406Ssklower param->p_rx_strat = TPRX_USE_CW; 23136406Ssklower } 23236406Ssklower break; 23336406Ssklower } 23436406Ssklower IFDEBUG(D_SETPARAMS) 23536406Ssklower printf("ack_strat 0x%x\n", param->p_ack_strat ); 23636406Ssklower ENDDEBUG 23736406Ssklower if((param->p_ack_strat != 0) && (param->p_ack_strat != 1)) { 23836406Ssklower if(cmd & TP_STRICT) { 23936406Ssklower error = EINVAL; 24036406Ssklower } else { 24136406Ssklower param->p_ack_strat = TPACK_WINDOW; 24236406Ssklower } 24336406Ssklower break; 24436406Ssklower } 24536406Ssklower if (param->p_tpdusize < TP_MIN_TPDUSIZE) { 24636406Ssklower if(cmd & TP_STRICT) { 24736406Ssklower error = EINVAL; 24836406Ssklower } else { 24936406Ssklower param->p_tpdusize = TP_MIN_TPDUSIZE; 25036406Ssklower } 25136406Ssklower break; 25236406Ssklower } 25336406Ssklower if (param->p_tpdusize > TP_TPDUSIZE) { 25436406Ssklower if(cmd & TP_STRICT) { 25536406Ssklower error = EINVAL; 25636406Ssklower } else { 25736406Ssklower param->p_tpdusize = TP_TPDUSIZE; 25836406Ssklower } 25936406Ssklower break; 26036406Ssklower } 26136406Ssklower break; 26236406Ssklower } 26336406Ssklower 26436406Ssklower if ((error==0) && (cmd & TP_FORCE)) { 26551996Ssklower long dusize = ((long)param->p_ptpdusize) << 7; 26647282Ssklower /* Enforce Negotation rules below */ 26736406Ssklower tpcb->tp_class = param->p_class; 26847282Ssklower if (tpcb->tp_use_checksum || param->p_use_checksum) 26947282Ssklower tpcb->tp_use_checksum = 1; 27047282Ssklower if (!tpcb->tp_xpd_service || !param->p_xpd_service) 27147282Ssklower tpcb->tp_xpd_service = 0; 27247282Ssklower if (!tpcb->tp_xtd_format || !param->p_xtd_format) 27347282Ssklower tpcb->tp_xtd_format = 0; 27451996Ssklower if (dusize) { 27551996Ssklower if (tpcb->tp_l_tpdusize > dusize) 27651996Ssklower tpcb->tp_l_tpdusize = dusize; 27751996Ssklower if (tpcb->tp_ptpdusize == 0 || 27851996Ssklower tpcb->tp_ptpdusize > param->p_ptpdusize) 27951996Ssklower tpcb->tp_ptpdusize = param->p_ptpdusize; 28051996Ssklower } else { 28151996Ssklower if (param->p_tpdusize != 0 && 28251996Ssklower tpcb->tp_tpdusize > param->p_tpdusize) 28351996Ssklower tpcb->tp_tpdusize = param->p_tpdusize; 28451996Ssklower tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize; 28551996Ssklower } 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 38350974Ssklower return ((tpcb->tp_nlproto->nlp_ctloutput)(cmd, optname, 38450974Ssklower tpcb->tp_npcb, *mp)); 38536406Ssklower goto done; 38650974Ssklower } else if ( level == SOL_SOCKET) { 38750974Ssklower if (optname == SO_RCVBUF && cmd == PRCO_SETOPT) { 38853688Ssklower u_long old_credit = tpcb->tp_maxlcredit; 38950974Ssklower tp_rsyset(tpcb); 39053688Ssklower if (tpcb->tp_rhiwat != so->so_rcv.sb_hiwat && 39153688Ssklower tpcb->tp_state == TP_OPEN && 39253688Ssklower (old_credit < tpcb->tp_maxlcredit)) 39353688Ssklower tp_emit(AK_TPDU_type, tpcb, 39453688Ssklower tpcb->tp_rcvnxt, 0, MNULL); 39553688Ssklower tpcb->tp_rhiwat = so->so_rcv.sb_hiwat; 39650974Ssklower } 39750974Ssklower goto done; 39836406Ssklower } else if ( level != SOL_TRANSPORT ) { 39936406Ssklower error = EOPNOTSUPP; goto done; 40036406Ssklower } 40136406Ssklower if (cmd != PRCO_GETOPT && cmd != PRCO_SETOPT) { 40236406Ssklower error = EOPNOTSUPP; goto done; 40336406Ssklower } 40436406Ssklower if ( so->so_error ) { 40536406Ssklower error = so->so_error; goto done; 40636406Ssklower } 40736406Ssklower 40836406Ssklower /* The only options allowed after connection is established 40936406Ssklower * are GET (anything) and SET DISC DATA and SET PERF MEAS 41036406Ssklower */ 41136406Ssklower if ( ((so->so_state & SS_ISCONNECTING)||(so->so_state & SS_ISCONNECTED)) 41236406Ssklower && 41336406Ssklower (cmd == PRCO_SETOPT && 41436406Ssklower optname != TPOPT_DISC_DATA && 41538841Ssklower optname != TPOPT_CFRM_DATA && 41636406Ssklower optname != TPOPT_PERF_MEAS && 41736406Ssklower optname != TPOPT_CDDATA_CLEAR ) ) { 41836406Ssklower error = EISCONN; goto done; 41936406Ssklower } 42036406Ssklower /* The only options allowed after disconnection are GET DISC DATA, 42136406Ssklower * and TPOPT_PSTATISTICS 42236406Ssklower * and they're not allowed if the ref timer has gone off, because 42336406Ssklower * the tpcb is gone 42436406Ssklower */ 42538841Ssklower if ((so->so_state & (SS_ISCONNECTED | SS_ISCONFIRMING)) == 0) { 42650435Ssklower if ( so->so_pcb == (caddr_t)0 ) { 42736406Ssklower error = ENOTCONN; goto done; 42836406Ssklower } 42936406Ssklower if ( (tpcb->tp_state == TP_REFWAIT || tpcb->tp_state == TP_CLOSING) && 43036406Ssklower (optname != TPOPT_DISC_DATA && optname != TPOPT_PSTATISTICS)) { 43136406Ssklower error = ENOTCONN; goto done; 43236406Ssklower } 43336406Ssklower } 43436406Ssklower 43537469Ssklower value = mtod(*mp, caddr_t); /* it's aligned, don't worry, 43637469Ssklower * but lint complains about it 43737469Ssklower */ 43836406Ssklower val_len = (*mp)->m_len; 43936406Ssklower 44036406Ssklower switch (optname) { 44136406Ssklower 44244424Ssklower case TPOPT_INTERCEPT: 44350648Ssklower #define INA(t) (((struct inpcb *)(t->tp_npcb))->inp_laddr.s_addr) 44450648Ssklower #define ISOA(t) (((struct isopcb *)(t->tp_npcb))->isop_laddr->siso_addr) 44550648Ssklower 44650236Ssklower if ((so->so_state & SS_PRIV) == 0) { 44750236Ssklower error = EPERM; 44850648Ssklower } else if (cmd != PRCO_SETOPT || tpcb->tp_state != TP_CLOSED || 44950648Ssklower (tpcb->tp_flags & TPF_GENERAL_ADDR) || 45050648Ssklower tpcb->tp_next == 0) 45144424Ssklower error = EINVAL; 45244424Ssklower else { 45350648Ssklower register struct tp_pcb *t; 45450648Ssklower error = EADDRINUSE; 45550648Ssklower for (t = tp_listeners; t; t = t->tp_nextlisten) 45650648Ssklower if ((t->tp_flags & TPF_GENERAL_ADDR) == 0 && 45750648Ssklower t->tp_domain == tpcb->tp_domain) 45850648Ssklower switch (tpcb->tp_domain) { 45950648Ssklower default: 46050648Ssklower goto done; 46150648Ssklower #ifdef INET 46250648Ssklower case AF_INET: 46350648Ssklower if (INA(t) == INA(tpcb)) 46450648Ssklower goto done; 46550648Ssklower continue; 46650648Ssklower #endif 46750648Ssklower #ifdef ISO 46850648Ssklower case AF_ISO: 46950648Ssklower if (bcmp(ISOA(t).isoa_genaddr, ISOA(tpcb).isoa_genaddr, 47050648Ssklower ISOA(t).isoa_len) == 0) 47150648Ssklower goto done; 47250648Ssklower continue; 47350648Ssklower #endif 47450648Ssklower } 47550648Ssklower tpcb->tp_lsuffixlen = 0; 47650648Ssklower tpcb->tp_state = TP_LISTENING; 47750648Ssklower error = 0; 47850648Ssklower remque(tpcb); 47950648Ssklower tpcb->tp_next = tpcb->tp_prev = tpcb; 48050648Ssklower tpcb->tp_nextlisten = tp_listeners; 48150648Ssklower tp_listeners = tpcb; 48244424Ssklower } 48344424Ssklower break; 48444424Ssklower 48536406Ssklower case TPOPT_MY_TSEL: 48636406Ssklower if ( cmd == PRCO_GETOPT ) { 48736406Ssklower ASSERT( tpcb->tp_lsuffixlen <= MAX_TSAP_SEL_LEN ); 48837469Ssklower bcopy((caddr_t)tpcb->tp_lsuffix, value, tpcb->tp_lsuffixlen); 48936406Ssklower (*mp)->m_len = tpcb->tp_lsuffixlen; 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_lsuffix, val_len); 49636406Ssklower tpcb->tp_lsuffixlen = val_len; 49736406Ssklower } 49836406Ssklower } 49936406Ssklower break; 50036406Ssklower 50136406Ssklower case TPOPT_PEER_TSEL: 50236406Ssklower if ( cmd == PRCO_GETOPT ) { 50336406Ssklower ASSERT( tpcb->tp_fsuffixlen <= MAX_TSAP_SEL_LEN ); 50437469Ssklower bcopy((caddr_t)tpcb->tp_fsuffix, value, tpcb->tp_fsuffixlen); 50536406Ssklower (*mp)->m_len = tpcb->tp_fsuffixlen; 50636406Ssklower } else /* cmd == PRCO_SETOPT */ { 50736406Ssklower if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { 50836406Ssklower printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); 50936406Ssklower error = EINVAL; 51036406Ssklower } else { 51137469Ssklower bcopy(value, (caddr_t)tpcb->tp_fsuffix, val_len); 51236406Ssklower tpcb->tp_fsuffixlen = val_len; 51336406Ssklower } 51436406Ssklower } 51536406Ssklower break; 51636406Ssklower 51736406Ssklower case TPOPT_FLAGS: 51836406Ssklower IFDEBUG(D_REQUEST) 51936406Ssklower printf("%s TPOPT_FLAGS value 0x%x *value 0x%x, flags 0x%x \n", 52036406Ssklower cmd==PRCO_GETOPT?"GET":"SET", 52136406Ssklower value, 52236406Ssklower *value, 52336406Ssklower tpcb->tp_flags); 52436406Ssklower ENDDEBUG 52536406Ssklower 52636406Ssklower if ( cmd == PRCO_GETOPT ) { 52736406Ssklower *(int *)value = (int)tpcb->tp_flags; 52836406Ssklower (*mp)->m_len = sizeof(u_int); 52936406Ssklower } else /* cmd == PRCO_SETOPT */ { 53036406Ssklower error = EINVAL; goto done; 53136406Ssklower } 53236406Ssklower break; 53336406Ssklower 53436406Ssklower case TPOPT_PARAMS: 53536406Ssklower /* This handles: 53636406Ssklower * timer values, 53736406Ssklower * class, use of transport expedited data, 53836406Ssklower * max tpdu size, checksum, xtd format and 53936406Ssklower * disconnect indications, and may get rid of connect/disc data 54036406Ssklower */ 54136406Ssklower IFDEBUG(D_SETPARAMS) 54236406Ssklower printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, 54336406Ssklower cmd==PRCO_GETOPT?"GET":"SET"); 54436406Ssklower ENDDEBUG 54536406Ssklower IFDEBUG(D_REQUEST) 54636406Ssklower printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, 54736406Ssklower cmd==PRCO_GETOPT?"GET":"SET"); 54836406Ssklower ENDDEBUG 54936406Ssklower 55036406Ssklower if ( cmd == PRCO_GETOPT ) { 55136406Ssklower *(struct tp_conn_param *)value = tpcb->_tp_param; 55236406Ssklower (*mp)->m_len = sizeof(tpcb->_tp_param); 55336406Ssklower } else /* cmd == PRCO_SETOPT */ { 55436406Ssklower if( (error = 55536406Ssklower tp_consistency(tpcb, TP_STRICT | TP_FORCE, 55636406Ssklower (struct tp_conn_param *)value))==0) { 55736406Ssklower /* 55836406Ssklower * tp_consistency doesn't copy the whole set of params 55936406Ssklower */ 56036406Ssklower tpcb->_tp_param = *(struct tp_conn_param *)value; 56136406Ssklower (*mp)->m_len = sizeof(tpcb->_tp_param); 56236406Ssklower } 56336406Ssklower } 56436406Ssklower break; 56536406Ssklower 56636406Ssklower case TPOPT_PSTATISTICS: 56736406Ssklower #ifdef TP_PERF_MEAS 56836406Ssklower if (cmd == PRCO_SETOPT) { 56936406Ssklower error = EINVAL; goto done; 57036406Ssklower } 57136406Ssklower IFPERF(tpcb) 57237469Ssklower if (*mp) { 57337469Ssklower struct mbuf * n; 57437469Ssklower do { 57537469Ssklower MFREE(*mp, n); 57637469Ssklower *mp = n; 57737469Ssklower } while (n); 57837469Ssklower } 57937469Ssklower *mp = m_copym(tpcb->tp_p_mbuf, (int)M_COPYALL, M_WAITOK); 58036406Ssklower ENDPERF 58136406Ssklower else { 58236406Ssklower error = EINVAL; goto done; 58336406Ssklower } 58436406Ssklower break; 58536406Ssklower #else 58636406Ssklower error = EOPNOTSUPP; 58736406Ssklower goto done; 58836406Ssklower #endif TP_PERF_MEAS 58936406Ssklower 59036406Ssklower case TPOPT_CDDATA_CLEAR: 59136406Ssklower if (cmd == PRCO_GETOPT) { 59236406Ssklower error = EINVAL; 59336406Ssklower } else { 59437469Ssklower if (tpcb->tp_ucddata) { 59538841Ssklower m_freem(tpcb->tp_ucddata); 59638841Ssklower tpcb->tp_ucddata = 0; 59736406Ssklower } 59836406Ssklower } 59936406Ssklower break; 60036406Ssklower 60138841Ssklower case TPOPT_CFRM_DATA: 60236406Ssklower case TPOPT_DISC_DATA: 60336406Ssklower case TPOPT_CONN_DATA: 60436406Ssklower if( tpcb->tp_class == TP_CLASS_0 ) { 60536406Ssklower error = EOPNOTSUPP; 60636406Ssklower break; 60736406Ssklower } 60836406Ssklower IFDEBUG(D_REQUEST) 60936406Ssklower printf("%s\n", optname==TPOPT_DISC_DATA?"DISC data":"CONN data"); 61036406Ssklower printf("m_len 0x%x, vallen 0x%x so_snd.cc 0x%x\n", 61136406Ssklower (*mp)->m_len, val_len, so->so_snd.sb_cc); 61236406Ssklower dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput: sosnd "); 61336406Ssklower ENDDEBUG 61436406Ssklower if (cmd == PRCO_SETOPT) { 61537469Ssklower int len = tpcb->tp_ucddata ? tpcb->tp_ucddata->m_len : 0; 61636406Ssklower /* can append connect data in several calls */ 61737469Ssklower if (len + val_len > 61836406Ssklower (optname==TPOPT_CONN_DATA?TP_MAX_CR_DATA:TP_MAX_DR_DATA) ) { 61936406Ssklower error = EMSGSIZE; goto done; 62036406Ssklower } 62136406Ssklower (*mp)->m_next = MNULL; 62236406Ssklower (*mp)->m_act = 0; 62337469Ssklower if (tpcb->tp_ucddata) 62437469Ssklower m_cat(tpcb->tp_ucddata, *mp); 62537469Ssklower else 62637469Ssklower tpcb->tp_ucddata = *mp; 62740241Ssklower IFDEBUG(D_REQUEST) 62840241Ssklower dump_mbuf(tpcb->tp_ucddata, "tp_ctloutput after CONN_DATA"); 62940241Ssklower ENDDEBUG 63036406Ssklower IFTRACE(D_REQUEST) 63136406Ssklower tptrace(TPPTmisc,"C/D DATA: flags snd.sbcc val_len", 63236406Ssklower tpcb->tp_flags, so->so_snd.sb_cc,val_len,0); 63336406Ssklower ENDTRACE 63450974Ssklower *mp = MNULL; 63540241Ssklower if (optname == TPOPT_CFRM_DATA && (so->so_state & SS_ISCONFIRMING)) 63640241Ssklower (void) tp_confirm(tpcb); 63736406Ssklower } 63836406Ssklower break; 63936406Ssklower 64036406Ssklower case TPOPT_PERF_MEAS: 64136406Ssklower #ifdef TP_PERF_MEAS 64236406Ssklower if (cmd == PRCO_GETOPT) { 64336406Ssklower *value = (u_int)tpcb->tp_perf_on; 64436406Ssklower (*mp)->m_len = sizeof(u_int); 64536406Ssklower } else if (cmd == PRCO_SETOPT) { 64636406Ssklower (*mp)->m_len = 0; 64736406Ssklower if ((*value) != 0 && (*value) != 1 ) 64836406Ssklower error = EINVAL; 64936406Ssklower else tpcb->tp_perf_on = (*value); 65036406Ssklower } 65136406Ssklower if( tpcb->tp_perf_on ) 65236406Ssklower error = tp_setup_perf(tpcb); 65336406Ssklower #else TP_PERF_MEAS 65436406Ssklower error = EOPNOTSUPP; 65536406Ssklower #endif TP_PERF_MEAS 65636406Ssklower break; 65736406Ssklower 65836406Ssklower default: 65936406Ssklower error = EOPNOTSUPP; 66036406Ssklower } 66136406Ssklower 66236406Ssklower done: 66336406Ssklower IFDEBUG(D_REQUEST) 66436406Ssklower dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput sosnd at end"); 66536406Ssklower dump_mbuf(*mp, "tp_ctloutput *mp"); 66636406Ssklower ENDDEBUG 66736406Ssklower /* 66836406Ssklower * sigh: getsockopt looks only at m_len : all output data must 66936406Ssklower * reside in the first mbuf 67036406Ssklower */ 67150974Ssklower if (*mp) { 67253688Ssklower if (cmd == PRCO_SETOPT) { 67350974Ssklower m_freem(*mp); 67453688Ssklower *mp = MNULL; 67553688Ssklower } else { 67650974Ssklower ASSERT ( m_compress(*mp, mp) <= MLEN ); 67750974Ssklower if (error) 67850974Ssklower (*mp)->m_len = 0; 67950974Ssklower IFDEBUG(D_REQUEST) 68050974Ssklower dump_mbuf(*mp, "tp_ctloutput *mp after compress"); 68150974Ssklower ENDDEBUG 68250974Ssklower } 68336406Ssklower } 68436406Ssklower splx(s); 68536406Ssklower return error; 68636406Ssklower } 687