149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*50974Ssklower * @(#)tp_output.c 7.13 (Berkeley) 09/03/91 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 4536406Ssklower #include "param.h" 4644424Ssklower #include "mbuf.h" 4736406Ssklower #include "systm.h" 4836406Ssklower #include "socket.h" 4936406Ssklower #include "socketvar.h" 5044424Ssklower #include "protosw.h" 5136406Ssklower #include "errno.h" 5236406Ssklower #include "time.h" 5337469Ssklower #include "tp_param.h" 5437469Ssklower #include "tp_user.h" 5537469Ssklower #include "tp_stat.h" 5637469Ssklower #include "tp_ip.h" 5744424Ssklower #include "tp_clnp.h" 5837469Ssklower #include "tp_timer.h" 5937469Ssklower #include "argo_debug.h" 6037469Ssklower #include "tp_pcb.h" 6137469Ssklower #include "tp_trace.h" 6250236Ssklower #include "kernel.h" 6336406Ssklower 6436406Ssklower #define TPDUSIZESHIFT 24 6536406Ssklower #define CLASSHIFT 16 6636406Ssklower 6736406Ssklower /* 6836406Ssklower * NAME: tp_consistency() 6936406Ssklower * 7036406Ssklower * CALLED FROM: 7136406Ssklower * tp_ctloutput(), tp_input() 7236406Ssklower * 7336406Ssklower * FUNCTION and ARGUMENTS: 7436406Ssklower * Checks the consistency of options and tpdusize with class, 7536406Ssklower * using the parameters passed in via (param). 7636406Ssklower * (cmd) may be TP_STRICT or TP_FORCE or both. 7736406Ssklower * Force means it will set all the values in (tpcb) to those in 7836406Ssklower * the input arguements iff no errors were encountered. 7936406Ssklower * Strict means that no inconsistency will be tolerated. If it's 8036406Ssklower * not used, checksum and tpdusize inconsistencies will be tolerated. 8136406Ssklower * The reason for this is that in some cases, when we're negotiating down 8236406Ssklower * from class 4, these options should be changed but should not 8336406Ssklower * cause negotiation to fail. 8436406Ssklower * 8536406Ssklower * RETURNS 8636406Ssklower * E* or EOK 8736406Ssklower * E* if the various parms aren't ok for a given class 8836406Ssklower * EOK if they are ok for a given class 8936406Ssklower */ 9036406Ssklower 9136406Ssklower int 9236406Ssklower tp_consistency( tpcb, cmd, param ) 9336406Ssklower u_int cmd; 9436406Ssklower struct tp_conn_param *param; 9536406Ssklower struct tp_pcb *tpcb; 9636406Ssklower { 9736406Ssklower register int error = EOK; 9836406Ssklower int class_to_use = tp_mask_to_num(param->p_class); 9936406Ssklower 10036406Ssklower IFTRACE(D_SETPARAMS) 10136406Ssklower tptrace(TPPTmisc, 10236406Ssklower "tp_consist enter class_to_use dontchange param.class cmd", 10336406Ssklower class_to_use, param->p_dont_change_params, param->p_class, cmd); 10436406Ssklower ENDTRACE 10536406Ssklower IFDEBUG(D_SETPARAMS) 10636406Ssklower printf("tp_consistency %s %s\n", 10736406Ssklower cmd& TP_FORCE? "TP_FORCE": "", 10836406Ssklower cmd& TP_STRICT? "TP_STRICT":""); 10936406Ssklower ENDDEBUG 11036406Ssklower if ((cmd & TP_FORCE) && (param->p_dont_change_params)) { 11136406Ssklower cmd &= ~TP_FORCE; 11236406Ssklower } 11336406Ssklower /* can switch net services within a domain, but 11436406Ssklower * cannot switch domains 11536406Ssklower */ 11636406Ssklower switch( param->p_netservice) { 11736406Ssklower case ISO_CONS: 11836406Ssklower case ISO_CLNS: 11936406Ssklower case ISO_COSNS: 12036406Ssklower /* param->p_netservice in ISO DOMAIN */ 12136406Ssklower if(tpcb->tp_domain != AF_ISO ) { 12236406Ssklower error = EINVAL; goto done; 12336406Ssklower } 12436406Ssklower break; 12536406Ssklower case IN_CLNS: 12636406Ssklower /* param->p_netservice in INET DOMAIN */ 12736406Ssklower if( tpcb->tp_domain != AF_INET ) { 12836406Ssklower error = EINVAL; goto done; 12936406Ssklower } 13036406Ssklower break; 13136406Ssklower /* no others not possible-> netservice is a 2-bit field! */ 13236406Ssklower } 13336406Ssklower 13436406Ssklower IFDEBUG(D_SETPARAMS) 13536406Ssklower printf("p_class 0x%x, class_to_use 0x%x\n", param->p_class, 13636406Ssklower class_to_use); 13736406Ssklower ENDDEBUG 13836406Ssklower if((param->p_netservice < 0) || (param->p_netservice > TP_MAX_NETSERVICES)){ 13936406Ssklower error = EINVAL; goto done; 14036406Ssklower } 14136406Ssklower if( (param->p_class & TP_CLASSES_IMPLEMENTED) == 0 ) { 14236406Ssklower error = EINVAL; goto done; 14336406Ssklower } 14436406Ssklower IFDEBUG(D_SETPARAMS) 14536406Ssklower printf("Nretrans 0x%x\n", param->p_Nretrans ); 14636406Ssklower ENDDEBUG 14736406Ssklower if( ( param->p_Nretrans < 1 ) || 14836406Ssklower (param->p_cr_ticks < 1) || (param->p_cc_ticks < 1) ) { 14936406Ssklower /* bad for any class because negot has to be done a la class 4 */ 15036406Ssklower error = EINVAL; goto done; 15136406Ssklower } 15236406Ssklower IFDEBUG(D_SETPARAMS) 15336406Ssklower printf("winsize 0x%x\n", param->p_winsize ); 15436406Ssklower ENDDEBUG 15536406Ssklower if( (param->p_winsize < 128 ) || 15636406Ssklower (param->p_winsize < param->p_tpdusize ) || 15736406Ssklower (param->p_winsize > ((1+SB_MAX)>>2 /* 1/4 of the max */)) ) { 15836406Ssklower error = EINVAL; goto done; 15936406Ssklower } else { 16036406Ssklower if( tpcb->tp_state == TP_CLOSED ) 16137469Ssklower soreserve(tpcb->tp_sock, (u_long)param->p_winsize, 16237469Ssklower (u_long)param->p_winsize); 16336406Ssklower } 16436406Ssklower IFDEBUG(D_SETPARAMS) 16536406Ssklower printf("use_csum 0x%x\n", param->p_use_checksum ); 16636406Ssklower printf("xtd_format 0x%x\n", param->p_xtd_format ); 16736406Ssklower printf("xpd_service 0x%x\n", param->p_xpd_service ); 16836406Ssklower printf("tpdusize 0x%x\n", param->p_tpdusize ); 16936406Ssklower printf("tpcb->flags 0x%x\n", tpcb->tp_flags ); 17036406Ssklower ENDDEBUG 17136406Ssklower switch( class_to_use ) { 17236406Ssklower 17336406Ssklower case 0: 17436406Ssklower /* do not use checksums, xtd format, or XPD */ 17536406Ssklower 17636406Ssklower if( param->p_use_checksum | param->p_xtd_format | param->p_xpd_service ) { 17736406Ssklower if(cmd & TP_STRICT) { 17836406Ssklower error = EINVAL; 17936406Ssklower } else { 18036406Ssklower param->p_use_checksum = 0; 18136406Ssklower param->p_xtd_format = 0; 18236406Ssklower param->p_xpd_service = 0; 18336406Ssklower } 18436406Ssklower break; 18536406Ssklower } 18636406Ssklower 18736406Ssklower if (param->p_tpdusize < TP_MIN_TPDUSIZE) { 18836406Ssklower if(cmd & TP_STRICT) { 18936406Ssklower error = EINVAL; 19036406Ssklower } else { 19136406Ssklower param->p_tpdusize = TP_MIN_TPDUSIZE; 19236406Ssklower } 19336406Ssklower break; 19436406Ssklower } 19536406Ssklower if (param->p_tpdusize > TP0_TPDUSIZE) { 19636406Ssklower if (cmd & TP_STRICT) { 19736406Ssklower error = EINVAL; 19836406Ssklower } else { 19936406Ssklower param->p_tpdusize = TP0_TPDUSIZE; 20036406Ssklower } 20136406Ssklower break; 20236406Ssklower } 20336406Ssklower 20436406Ssklower /* connect/disc data not allowed for class 0 */ 20537469Ssklower if (tpcb->tp_ucddata) { 20636406Ssklower if(cmd & TP_STRICT) { 20736406Ssklower error = EINVAL; 20836406Ssklower } else if(cmd & TP_FORCE) { 20937469Ssklower m_freem(tpcb->tp_ucddata); 21037469Ssklower tpcb->tp_ucddata = 0; 21136406Ssklower } 21236406Ssklower } 21336406Ssklower break; 21436406Ssklower 21536406Ssklower case 4: 21636406Ssklower IFDEBUG(D_SETPARAMS) 21736406Ssklower printf("dt_ticks 0x%x\n", param->p_dt_ticks ); 21836406Ssklower printf("x_ticks 0x%x\n", param->p_x_ticks ); 21936406Ssklower printf("dr_ticks 0x%x\n", param->p_dr_ticks ); 22036406Ssklower printf("keepalive 0x%x\n", param->p_keepalive_ticks ); 22136406Ssklower printf("sendack 0x%x\n", param->p_sendack_ticks ); 22236406Ssklower printf("inact 0x%x\n", param->p_inact_ticks ); 22336406Ssklower printf("ref 0x%x\n", param->p_ref_ticks ); 22436406Ssklower ENDDEBUG 22536406Ssklower if( (param->p_class & TP_CLASS_4 ) && ( 22636406Ssklower (param->p_dt_ticks < 1) || (param->p_dr_ticks < 1) || 22736406Ssklower (param->p_x_ticks < 1) || (param->p_keepalive_ticks < 1) || 22836406Ssklower (param->p_sendack_ticks < 1) || (param->p_ref_ticks < 1) || 22936406Ssklower (param->p_inact_ticks < 1) ) ) { 23036406Ssklower error = EINVAL; 23136406Ssklower break; 23236406Ssklower } 23336406Ssklower IFDEBUG(D_SETPARAMS) 23436406Ssklower printf("rx_strat 0x%x\n", param->p_rx_strat ); 23536406Ssklower ENDDEBUG 23636406Ssklower if(param->p_rx_strat > 23736406Ssklower ( TPRX_USE_CW | TPRX_EACH | TPRX_FASTSTART) ) { 23836406Ssklower if(cmd & TP_STRICT) { 23936406Ssklower error = EINVAL; 24036406Ssklower } else { 24136406Ssklower param->p_rx_strat = TPRX_USE_CW; 24236406Ssklower } 24336406Ssklower break; 24436406Ssklower } 24536406Ssklower IFDEBUG(D_SETPARAMS) 24636406Ssklower printf("ack_strat 0x%x\n", param->p_ack_strat ); 24736406Ssklower ENDDEBUG 24836406Ssklower if((param->p_ack_strat != 0) && (param->p_ack_strat != 1)) { 24936406Ssklower if(cmd & TP_STRICT) { 25036406Ssklower error = EINVAL; 25136406Ssklower } else { 25236406Ssklower param->p_ack_strat = TPACK_WINDOW; 25336406Ssklower } 25436406Ssklower break; 25536406Ssklower } 25636406Ssklower if (param->p_tpdusize < TP_MIN_TPDUSIZE) { 25736406Ssklower if(cmd & TP_STRICT) { 25836406Ssklower error = EINVAL; 25936406Ssklower } else { 26036406Ssklower param->p_tpdusize = TP_MIN_TPDUSIZE; 26136406Ssklower } 26236406Ssklower break; 26336406Ssklower } 26436406Ssklower if (param->p_tpdusize > TP_TPDUSIZE) { 26536406Ssklower if(cmd & TP_STRICT) { 26636406Ssklower error = EINVAL; 26736406Ssklower } else { 26836406Ssklower param->p_tpdusize = TP_TPDUSIZE; 26936406Ssklower } 27036406Ssklower break; 27136406Ssklower } 27236406Ssklower break; 27336406Ssklower } 27436406Ssklower 27536406Ssklower if ((error==0) && (cmd & TP_FORCE)) { 27647282Ssklower /* Enforce Negotation rules below */ 27747282Ssklower if (tpcb->tp_tpdusize > param->p_tpdusize) 27847282Ssklower tpcb->tp_tpdusize = param->p_tpdusize; 27936406Ssklower tpcb->tp_class = param->p_class; 28047282Ssklower if (tpcb->tp_use_checksum || param->p_use_checksum) 28147282Ssklower tpcb->tp_use_checksum = 1; 28247282Ssklower if (!tpcb->tp_xpd_service || !param->p_xpd_service) 28347282Ssklower tpcb->tp_xpd_service = 0; 28447282Ssklower if (!tpcb->tp_xtd_format || !param->p_xtd_format) 28547282Ssklower tpcb->tp_xtd_format = 0; 28636406Ssklower } 28736406Ssklower 28836406Ssklower done: 28936406Ssklower 29036406Ssklower IFTRACE(D_CONN) 29136406Ssklower tptrace(TPPTmisc, "tp_consist returns class xtdfmt cmd", 29236406Ssklower error, tpcb->tp_class, tpcb->tp_xtd_format, cmd); 29336406Ssklower ENDTRACE 29436406Ssklower IFDEBUG(D_CONN) 29536406Ssklower printf( 29636406Ssklower "tp_consist rtns 0x%x class 0x%x xtd_fmt 0x%x cmd 0x%x\n", 29736406Ssklower error, tpcb->tp_class, tpcb->tp_xtd_format, cmd); 29836406Ssklower ENDDEBUG 29936406Ssklower return error; 30036406Ssklower } 30136406Ssklower 30236406Ssklower /* 30336406Ssklower * NAME: tp_ctloutput() 30436406Ssklower * 30536406Ssklower * CALLED FROM: 30636406Ssklower * [sg]etsockopt(), via so[sg]etopt(). 30736406Ssklower * 30836406Ssklower * FUNCTION and ARGUMENTS: 30936406Ssklower * Implements the socket options at transport level. 31037536Smckusick * (cmd) is either PRCO_SETOPT or PRCO_GETOPT (see ../sys/protosw.h). 31136406Ssklower * (so) is the socket. 31237536Smckusick * (level) is SOL_TRANSPORT (see ../sys/socket.h) 31336406Ssklower * (optname) is the particular command or option to be set. 31436406Ssklower * (**mp) is an mbuf structure. 31536406Ssklower * 31636406Ssklower * RETURN VALUE: 31736406Ssklower * ENOTSOCK if the socket hasn't got an associated tpcb 31836406Ssklower * EINVAL if 31936406Ssklower * trying to set window too big 32036406Ssklower * trying to set illegal max tpdu size 32136406Ssklower * trying to set illegal credit fraction 32236406Ssklower * trying to use unknown or unimplemented class of TP 32336406Ssklower * structure passed to set timer values is wrong size 32436406Ssklower * illegal combination of command/GET-SET option, 32536406Ssklower * e.g., GET w/ TPOPT_CDDATA_CLEAR: 32636406Ssklower * EOPNOTSUPP if the level isn't transport, or command is neither GET nor SET 32736406Ssklower * or if the transport-specific command is not implemented 32836406Ssklower * EISCONN if trying a command that isn't allowed after a connection 32936406Ssklower * is established 33036406Ssklower * ENOTCONN if trying a command that is allowed only if a connection is 33136406Ssklower * established 33236406Ssklower * EMSGSIZE if trying to give too much data on connect/disconnect 33336406Ssklower * 33436406Ssklower * SIDE EFFECTS: 33536406Ssklower * 33636406Ssklower * NOTES: 33736406Ssklower */ 33836406Ssklower ProtoHook 33936406Ssklower tp_ctloutput(cmd, so, level, optname, mp) 34036406Ssklower int cmd, level, optname; 34136406Ssklower struct socket *so; 34236406Ssklower struct mbuf **mp; 34336406Ssklower { 34436406Ssklower struct tp_pcb *tpcb = sototpcb(so); 34536406Ssklower int s = splnet(); 34637469Ssklower caddr_t value; 34737469Ssklower unsigned val_len; 34836406Ssklower int error = 0; 34936406Ssklower 35036406Ssklower IFTRACE(D_REQUEST) 35136406Ssklower tptrace(TPPTmisc, "tp_ctloutput cmd so optname mp", 35236406Ssklower cmd, so, optname, mp); 35336406Ssklower ENDTRACE 35436406Ssklower IFDEBUG(D_REQUEST) 35536406Ssklower printf( 35636406Ssklower "tp_ctloutput so 0x%x cmd 0x%x optname 0x%x, mp 0x%x *mp 0x%x tpcb 0x%x\n", 35736406Ssklower so, cmd, optname, mp, mp?*mp:0, tpcb); 35836406Ssklower ENDDEBUG 35936406Ssklower if( tpcb == (struct tp_pcb *)0 ) { 36036406Ssklower error = ENOTSOCK; goto done; 36136406Ssklower } 36236406Ssklower if(*mp == MNULL) { 36336406Ssklower register struct mbuf *m; 36436406Ssklower 36536406Ssklower MGET(m, M_DONTWAIT, TPMT_SONAME); /* does off, type, next */ 36636406Ssklower if (m == NULL) { 36736406Ssklower splx(s); 36836406Ssklower return ENOBUFS; 36936406Ssklower } 37036406Ssklower m->m_len = 0; 37136406Ssklower m->m_act = 0; 37236406Ssklower *mp = m; 37336406Ssklower } 37436406Ssklower 37536406Ssklower /* 37636406Ssklower * Hook so one can set network options via a tp socket. 37736406Ssklower */ 37836406Ssklower if ( level == SOL_NETWORK ) { 37936406Ssklower if ((tpcb->tp_nlproto == NULL) || (tpcb->tp_npcb == NULL)) 38036406Ssklower error = ENOTSOCK; 38136406Ssklower else if (tpcb->tp_nlproto->nlp_ctloutput == NULL) 38236406Ssklower error = EOPNOTSUPP; 38336406Ssklower else 384*50974Ssklower return ((tpcb->tp_nlproto->nlp_ctloutput)(cmd, optname, 385*50974Ssklower tpcb->tp_npcb, *mp)); 38636406Ssklower goto done; 387*50974Ssklower } else if ( level == SOL_SOCKET) { 388*50974Ssklower if (optname == SO_RCVBUF && cmd == PRCO_SETOPT) { 389*50974Ssklower tp_rsyset(tpcb); 390*50974Ssklower } 391*50974Ssklower goto done; 39236406Ssklower } else if ( level != SOL_TRANSPORT ) { 39336406Ssklower error = EOPNOTSUPP; goto done; 39436406Ssklower } 39536406Ssklower if (cmd != PRCO_GETOPT && cmd != PRCO_SETOPT) { 39636406Ssklower error = EOPNOTSUPP; goto done; 39736406Ssklower } 39836406Ssklower if ( so->so_error ) { 39936406Ssklower error = so->so_error; goto done; 40036406Ssklower } 40136406Ssklower 40236406Ssklower /* The only options allowed after connection is established 40336406Ssklower * are GET (anything) and SET DISC DATA and SET PERF MEAS 40436406Ssklower */ 40536406Ssklower if ( ((so->so_state & SS_ISCONNECTING)||(so->so_state & SS_ISCONNECTED)) 40636406Ssklower && 40736406Ssklower (cmd == PRCO_SETOPT && 40836406Ssklower optname != TPOPT_DISC_DATA && 40938841Ssklower optname != TPOPT_CFRM_DATA && 41036406Ssklower optname != TPOPT_PERF_MEAS && 41136406Ssklower optname != TPOPT_CDDATA_CLEAR ) ) { 41236406Ssklower error = EISCONN; goto done; 41336406Ssklower } 41436406Ssklower /* The only options allowed after disconnection are GET DISC DATA, 41536406Ssklower * and TPOPT_PSTATISTICS 41636406Ssklower * and they're not allowed if the ref timer has gone off, because 41736406Ssklower * the tpcb is gone 41836406Ssklower */ 41938841Ssklower if ((so->so_state & (SS_ISCONNECTED | SS_ISCONFIRMING)) == 0) { 42050435Ssklower if ( so->so_pcb == (caddr_t)0 ) { 42136406Ssklower error = ENOTCONN; goto done; 42236406Ssklower } 42336406Ssklower if ( (tpcb->tp_state == TP_REFWAIT || tpcb->tp_state == TP_CLOSING) && 42436406Ssklower (optname != TPOPT_DISC_DATA && optname != TPOPT_PSTATISTICS)) { 42536406Ssklower error = ENOTCONN; goto done; 42636406Ssklower } 42736406Ssklower } 42836406Ssklower 42937469Ssklower value = mtod(*mp, caddr_t); /* it's aligned, don't worry, 43037469Ssklower * but lint complains about it 43137469Ssklower */ 43236406Ssklower val_len = (*mp)->m_len; 43336406Ssklower 43436406Ssklower switch (optname) { 43536406Ssklower 43644424Ssklower case TPOPT_INTERCEPT: 43750648Ssklower #define INA(t) (((struct inpcb *)(t->tp_npcb))->inp_laddr.s_addr) 43850648Ssklower #define ISOA(t) (((struct isopcb *)(t->tp_npcb))->isop_laddr->siso_addr) 43950648Ssklower 44050236Ssklower if ((so->so_state & SS_PRIV) == 0) { 44150236Ssklower error = EPERM; 44250648Ssklower } else if (cmd != PRCO_SETOPT || tpcb->tp_state != TP_CLOSED || 44350648Ssklower (tpcb->tp_flags & TPF_GENERAL_ADDR) || 44450648Ssklower tpcb->tp_next == 0) 44544424Ssklower error = EINVAL; 44644424Ssklower else { 44750648Ssklower register struct tp_pcb *t; 44850648Ssklower error = EADDRINUSE; 44950648Ssklower for (t = tp_listeners; t; t = t->tp_nextlisten) 45050648Ssklower if ((t->tp_flags & TPF_GENERAL_ADDR) == 0 && 45150648Ssklower t->tp_domain == tpcb->tp_domain) 45250648Ssklower switch (tpcb->tp_domain) { 45350648Ssklower default: 45450648Ssklower goto done; 45550648Ssklower #ifdef INET 45650648Ssklower case AF_INET: 45750648Ssklower if (INA(t) == INA(tpcb)) 45850648Ssklower goto done; 45950648Ssklower continue; 46050648Ssklower #endif 46150648Ssklower #ifdef ISO 46250648Ssklower case AF_ISO: 46350648Ssklower if (bcmp(ISOA(t).isoa_genaddr, ISOA(tpcb).isoa_genaddr, 46450648Ssklower ISOA(t).isoa_len) == 0) 46550648Ssklower goto done; 46650648Ssklower continue; 46750648Ssklower #endif 46850648Ssklower } 46950648Ssklower tpcb->tp_lsuffixlen = 0; 47050648Ssklower tpcb->tp_state = TP_LISTENING; 47150648Ssklower error = 0; 47250648Ssklower remque(tpcb); 47350648Ssklower tpcb->tp_next = tpcb->tp_prev = tpcb; 47450648Ssklower tpcb->tp_nextlisten = tp_listeners; 47550648Ssklower tp_listeners = tpcb; 47644424Ssklower } 47744424Ssklower break; 47844424Ssklower 47936406Ssklower case TPOPT_MY_TSEL: 48036406Ssklower if ( cmd == PRCO_GETOPT ) { 48136406Ssklower ASSERT( tpcb->tp_lsuffixlen <= MAX_TSAP_SEL_LEN ); 48237469Ssklower bcopy((caddr_t)tpcb->tp_lsuffix, value, tpcb->tp_lsuffixlen); 48336406Ssklower (*mp)->m_len = tpcb->tp_lsuffixlen; 48436406Ssklower } else /* cmd == PRCO_SETOPT */ { 48536406Ssklower if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { 48636406Ssklower printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); 48736406Ssklower error = EINVAL; 48836406Ssklower } else { 48937469Ssklower bcopy(value, (caddr_t)tpcb->tp_lsuffix, val_len); 49036406Ssklower tpcb->tp_lsuffixlen = val_len; 49136406Ssklower } 49236406Ssklower } 49336406Ssklower break; 49436406Ssklower 49536406Ssklower case TPOPT_PEER_TSEL: 49636406Ssklower if ( cmd == PRCO_GETOPT ) { 49736406Ssklower ASSERT( tpcb->tp_fsuffixlen <= MAX_TSAP_SEL_LEN ); 49837469Ssklower bcopy((caddr_t)tpcb->tp_fsuffix, value, tpcb->tp_fsuffixlen); 49936406Ssklower (*mp)->m_len = tpcb->tp_fsuffixlen; 50036406Ssklower } else /* cmd == PRCO_SETOPT */ { 50136406Ssklower if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { 50236406Ssklower printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); 50336406Ssklower error = EINVAL; 50436406Ssklower } else { 50537469Ssklower bcopy(value, (caddr_t)tpcb->tp_fsuffix, val_len); 50636406Ssklower tpcb->tp_fsuffixlen = val_len; 50736406Ssklower } 50836406Ssklower } 50936406Ssklower break; 51036406Ssklower 51136406Ssklower case TPOPT_FLAGS: 51236406Ssklower IFDEBUG(D_REQUEST) 51336406Ssklower printf("%s TPOPT_FLAGS value 0x%x *value 0x%x, flags 0x%x \n", 51436406Ssklower cmd==PRCO_GETOPT?"GET":"SET", 51536406Ssklower value, 51636406Ssklower *value, 51736406Ssklower tpcb->tp_flags); 51836406Ssklower ENDDEBUG 51936406Ssklower 52036406Ssklower if ( cmd == PRCO_GETOPT ) { 52136406Ssklower *(int *)value = (int)tpcb->tp_flags; 52236406Ssklower (*mp)->m_len = sizeof(u_int); 52336406Ssklower } else /* cmd == PRCO_SETOPT */ { 52436406Ssklower error = EINVAL; goto done; 52536406Ssklower } 52636406Ssklower break; 52736406Ssklower 52836406Ssklower case TPOPT_PARAMS: 52936406Ssklower /* This handles: 53036406Ssklower * timer values, 53136406Ssklower * class, use of transport expedited data, 53236406Ssklower * max tpdu size, checksum, xtd format and 53336406Ssklower * disconnect indications, and may get rid of connect/disc data 53436406Ssklower */ 53536406Ssklower IFDEBUG(D_SETPARAMS) 53636406Ssklower printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, 53736406Ssklower cmd==PRCO_GETOPT?"GET":"SET"); 53836406Ssklower ENDDEBUG 53936406Ssklower IFDEBUG(D_REQUEST) 54036406Ssklower printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, 54136406Ssklower cmd==PRCO_GETOPT?"GET":"SET"); 54236406Ssklower ENDDEBUG 54336406Ssklower 54436406Ssklower if ( cmd == PRCO_GETOPT ) { 54536406Ssklower *(struct tp_conn_param *)value = tpcb->_tp_param; 54636406Ssklower (*mp)->m_len = sizeof(tpcb->_tp_param); 54736406Ssklower } else /* cmd == PRCO_SETOPT */ { 54836406Ssklower if( (error = 54936406Ssklower tp_consistency(tpcb, TP_STRICT | TP_FORCE, 55036406Ssklower (struct tp_conn_param *)value))==0) { 55136406Ssklower /* 55236406Ssklower * tp_consistency doesn't copy the whole set of params 55336406Ssklower */ 55436406Ssklower tpcb->_tp_param = *(struct tp_conn_param *)value; 55536406Ssklower (*mp)->m_len = sizeof(tpcb->_tp_param); 55636406Ssklower } 55736406Ssklower } 55836406Ssklower break; 55936406Ssklower 56036406Ssklower case TPOPT_PSTATISTICS: 56136406Ssklower #ifdef TP_PERF_MEAS 56236406Ssklower if (cmd == PRCO_SETOPT) { 56336406Ssklower error = EINVAL; goto done; 56436406Ssklower } 56536406Ssklower IFPERF(tpcb) 56637469Ssklower if (*mp) { 56737469Ssklower struct mbuf * n; 56837469Ssklower do { 56937469Ssklower MFREE(*mp, n); 57037469Ssklower *mp = n; 57137469Ssklower } while (n); 57237469Ssklower } 57337469Ssklower *mp = m_copym(tpcb->tp_p_mbuf, (int)M_COPYALL, M_WAITOK); 57436406Ssklower ENDPERF 57536406Ssklower else { 57636406Ssklower error = EINVAL; goto done; 57736406Ssklower } 57836406Ssklower break; 57936406Ssklower #else 58036406Ssklower error = EOPNOTSUPP; 58136406Ssklower goto done; 58236406Ssklower #endif TP_PERF_MEAS 58336406Ssklower 58436406Ssklower case TPOPT_CDDATA_CLEAR: 58536406Ssklower if (cmd == PRCO_GETOPT) { 58636406Ssklower error = EINVAL; 58736406Ssklower } else { 58837469Ssklower if (tpcb->tp_ucddata) { 58938841Ssklower m_freem(tpcb->tp_ucddata); 59038841Ssklower tpcb->tp_ucddata = 0; 59136406Ssklower } 59236406Ssklower } 59336406Ssklower break; 59436406Ssklower 59538841Ssklower case TPOPT_CFRM_DATA: 59636406Ssklower case TPOPT_DISC_DATA: 59736406Ssklower case TPOPT_CONN_DATA: 59836406Ssklower if( tpcb->tp_class == TP_CLASS_0 ) { 59936406Ssklower error = EOPNOTSUPP; 60036406Ssklower break; 60136406Ssklower } 60236406Ssklower IFDEBUG(D_REQUEST) 60336406Ssklower printf("%s\n", optname==TPOPT_DISC_DATA?"DISC data":"CONN data"); 60436406Ssklower printf("m_len 0x%x, vallen 0x%x so_snd.cc 0x%x\n", 60536406Ssklower (*mp)->m_len, val_len, so->so_snd.sb_cc); 60636406Ssklower dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput: sosnd "); 60736406Ssklower ENDDEBUG 60836406Ssklower if (cmd == PRCO_SETOPT) { 60937469Ssklower int len = tpcb->tp_ucddata ? tpcb->tp_ucddata->m_len : 0; 61036406Ssklower /* can append connect data in several calls */ 61137469Ssklower if (len + val_len > 61236406Ssklower (optname==TPOPT_CONN_DATA?TP_MAX_CR_DATA:TP_MAX_DR_DATA) ) { 61336406Ssklower error = EMSGSIZE; goto done; 61436406Ssklower } 61536406Ssklower (*mp)->m_next = MNULL; 61636406Ssklower (*mp)->m_act = 0; 61737469Ssklower if (tpcb->tp_ucddata) 61837469Ssklower m_cat(tpcb->tp_ucddata, *mp); 61937469Ssklower else 62037469Ssklower tpcb->tp_ucddata = *mp; 62140241Ssklower IFDEBUG(D_REQUEST) 62240241Ssklower dump_mbuf(tpcb->tp_ucddata, "tp_ctloutput after CONN_DATA"); 62340241Ssklower ENDDEBUG 62436406Ssklower IFTRACE(D_REQUEST) 62536406Ssklower tptrace(TPPTmisc,"C/D DATA: flags snd.sbcc val_len", 62636406Ssklower tpcb->tp_flags, so->so_snd.sb_cc,val_len,0); 62736406Ssklower ENDTRACE 628*50974Ssklower *mp = MNULL; 62940241Ssklower if (optname == TPOPT_CFRM_DATA && (so->so_state & SS_ISCONFIRMING)) 63040241Ssklower (void) tp_confirm(tpcb); 63136406Ssklower } 63236406Ssklower break; 63336406Ssklower 63436406Ssklower case TPOPT_PERF_MEAS: 63536406Ssklower #ifdef TP_PERF_MEAS 63636406Ssklower if (cmd == PRCO_GETOPT) { 63736406Ssklower *value = (u_int)tpcb->tp_perf_on; 63836406Ssklower (*mp)->m_len = sizeof(u_int); 63936406Ssklower } else if (cmd == PRCO_SETOPT) { 64036406Ssklower (*mp)->m_len = 0; 64136406Ssklower if ((*value) != 0 && (*value) != 1 ) 64236406Ssklower error = EINVAL; 64336406Ssklower else tpcb->tp_perf_on = (*value); 64436406Ssklower } 64536406Ssklower if( tpcb->tp_perf_on ) 64636406Ssklower error = tp_setup_perf(tpcb); 64736406Ssklower #else TP_PERF_MEAS 64836406Ssklower error = EOPNOTSUPP; 64936406Ssklower #endif TP_PERF_MEAS 65036406Ssklower break; 65136406Ssklower 65236406Ssklower default: 65336406Ssklower error = EOPNOTSUPP; 65436406Ssklower } 65536406Ssklower 65636406Ssklower done: 65736406Ssklower IFDEBUG(D_REQUEST) 65836406Ssklower dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput sosnd at end"); 65936406Ssklower dump_mbuf(*mp, "tp_ctloutput *mp"); 66036406Ssklower ENDDEBUG 66136406Ssklower /* 66236406Ssklower * sigh: getsockopt looks only at m_len : all output data must 66336406Ssklower * reside in the first mbuf 66436406Ssklower */ 665*50974Ssklower if (*mp) { 666*50974Ssklower if (cmd == PRCO_SETOPT) 667*50974Ssklower m_freem(*mp); 668*50974Ssklower else { 669*50974Ssklower ASSERT ( m_compress(*mp, mp) <= MLEN ); 670*50974Ssklower if (error) 671*50974Ssklower (*mp)->m_len = 0; 672*50974Ssklower IFDEBUG(D_REQUEST) 673*50974Ssklower dump_mbuf(*mp, "tp_ctloutput *mp after compress"); 674*50974Ssklower ENDDEBUG 675*50974Ssklower } 67636406Ssklower } 67736406Ssklower splx(s); 67836406Ssklower return error; 67936406Ssklower } 680