149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*53688Ssklower * @(#)tp_output.c 7.16 (Berkeley) 05/27/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 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("use_csum 0x%x\n", param->p_use_checksum ); 15436406Ssklower printf("xtd_format 0x%x\n", param->p_xtd_format ); 15536406Ssklower printf("xpd_service 0x%x\n", param->p_xpd_service ); 15636406Ssklower printf("tpdusize 0x%x\n", param->p_tpdusize ); 15736406Ssklower printf("tpcb->flags 0x%x\n", tpcb->tp_flags ); 15836406Ssklower ENDDEBUG 15936406Ssklower switch( class_to_use ) { 16036406Ssklower 16136406Ssklower case 0: 16236406Ssklower /* do not use checksums, xtd format, or XPD */ 16336406Ssklower 16436406Ssklower if( param->p_use_checksum | param->p_xtd_format | param->p_xpd_service ) { 16536406Ssklower if(cmd & TP_STRICT) { 16636406Ssklower error = EINVAL; 16736406Ssklower } else { 16836406Ssklower param->p_use_checksum = 0; 16936406Ssklower param->p_xtd_format = 0; 17036406Ssklower param->p_xpd_service = 0; 17136406Ssklower } 17236406Ssklower break; 17336406Ssklower } 17436406Ssklower 17536406Ssklower if (param->p_tpdusize < TP_MIN_TPDUSIZE) { 17636406Ssklower if(cmd & TP_STRICT) { 17736406Ssklower error = EINVAL; 17836406Ssklower } else { 17936406Ssklower param->p_tpdusize = TP_MIN_TPDUSIZE; 18036406Ssklower } 18136406Ssklower break; 18236406Ssklower } 18336406Ssklower if (param->p_tpdusize > TP0_TPDUSIZE) { 18436406Ssklower if (cmd & TP_STRICT) { 18536406Ssklower error = EINVAL; 18636406Ssklower } else { 18736406Ssklower param->p_tpdusize = TP0_TPDUSIZE; 18836406Ssklower } 18936406Ssklower break; 19036406Ssklower } 19136406Ssklower 19236406Ssklower /* connect/disc data not allowed for class 0 */ 19337469Ssklower if (tpcb->tp_ucddata) { 19436406Ssklower if(cmd & TP_STRICT) { 19536406Ssklower error = EINVAL; 19636406Ssklower } else if(cmd & TP_FORCE) { 19737469Ssklower m_freem(tpcb->tp_ucddata); 19837469Ssklower tpcb->tp_ucddata = 0; 19936406Ssklower } 20036406Ssklower } 20136406Ssklower break; 20236406Ssklower 20336406Ssklower case 4: 20436406Ssklower IFDEBUG(D_SETPARAMS) 20536406Ssklower printf("dt_ticks 0x%x\n", param->p_dt_ticks ); 20636406Ssklower printf("x_ticks 0x%x\n", param->p_x_ticks ); 20736406Ssklower printf("dr_ticks 0x%x\n", param->p_dr_ticks ); 20836406Ssklower printf("keepalive 0x%x\n", param->p_keepalive_ticks ); 20936406Ssklower printf("sendack 0x%x\n", param->p_sendack_ticks ); 21036406Ssklower printf("inact 0x%x\n", param->p_inact_ticks ); 21136406Ssklower printf("ref 0x%x\n", param->p_ref_ticks ); 21236406Ssklower ENDDEBUG 21336406Ssklower if( (param->p_class & TP_CLASS_4 ) && ( 21436406Ssklower (param->p_dt_ticks < 1) || (param->p_dr_ticks < 1) || 21536406Ssklower (param->p_x_ticks < 1) || (param->p_keepalive_ticks < 1) || 21636406Ssklower (param->p_sendack_ticks < 1) || (param->p_ref_ticks < 1) || 21736406Ssklower (param->p_inact_ticks < 1) ) ) { 21836406Ssklower error = EINVAL; 21936406Ssklower break; 22036406Ssklower } 22136406Ssklower IFDEBUG(D_SETPARAMS) 22236406Ssklower printf("rx_strat 0x%x\n", param->p_rx_strat ); 22336406Ssklower ENDDEBUG 22436406Ssklower if(param->p_rx_strat > 22536406Ssklower ( TPRX_USE_CW | TPRX_EACH | TPRX_FASTSTART) ) { 22636406Ssklower if(cmd & TP_STRICT) { 22736406Ssklower error = EINVAL; 22836406Ssklower } else { 22936406Ssklower param->p_rx_strat = TPRX_USE_CW; 23036406Ssklower } 23136406Ssklower break; 23236406Ssklower } 23336406Ssklower IFDEBUG(D_SETPARAMS) 23436406Ssklower printf("ack_strat 0x%x\n", param->p_ack_strat ); 23536406Ssklower ENDDEBUG 23636406Ssklower if((param->p_ack_strat != 0) && (param->p_ack_strat != 1)) { 23736406Ssklower if(cmd & TP_STRICT) { 23836406Ssklower error = EINVAL; 23936406Ssklower } else { 24036406Ssklower param->p_ack_strat = TPACK_WINDOW; 24136406Ssklower } 24236406Ssklower break; 24336406Ssklower } 24436406Ssklower if (param->p_tpdusize < TP_MIN_TPDUSIZE) { 24536406Ssklower if(cmd & TP_STRICT) { 24636406Ssklower error = EINVAL; 24736406Ssklower } else { 24836406Ssklower param->p_tpdusize = TP_MIN_TPDUSIZE; 24936406Ssklower } 25036406Ssklower break; 25136406Ssklower } 25236406Ssklower if (param->p_tpdusize > TP_TPDUSIZE) { 25336406Ssklower if(cmd & TP_STRICT) { 25436406Ssklower error = EINVAL; 25536406Ssklower } else { 25636406Ssklower param->p_tpdusize = TP_TPDUSIZE; 25736406Ssklower } 25836406Ssklower break; 25936406Ssklower } 26036406Ssklower break; 26136406Ssklower } 26236406Ssklower 26336406Ssklower if ((error==0) && (cmd & TP_FORCE)) { 26451996Ssklower long dusize = ((long)param->p_ptpdusize) << 7; 26547282Ssklower /* Enforce Negotation rules below */ 26636406Ssklower tpcb->tp_class = param->p_class; 26747282Ssklower if (tpcb->tp_use_checksum || param->p_use_checksum) 26847282Ssklower tpcb->tp_use_checksum = 1; 26947282Ssklower if (!tpcb->tp_xpd_service || !param->p_xpd_service) 27047282Ssklower tpcb->tp_xpd_service = 0; 27147282Ssklower if (!tpcb->tp_xtd_format || !param->p_xtd_format) 27247282Ssklower tpcb->tp_xtd_format = 0; 27351996Ssklower if (dusize) { 27451996Ssklower if (tpcb->tp_l_tpdusize > dusize) 27551996Ssklower tpcb->tp_l_tpdusize = dusize; 27651996Ssklower if (tpcb->tp_ptpdusize == 0 || 27751996Ssklower tpcb->tp_ptpdusize > param->p_ptpdusize) 27851996Ssklower tpcb->tp_ptpdusize = param->p_ptpdusize; 27951996Ssklower } else { 28051996Ssklower if (param->p_tpdusize != 0 && 28151996Ssklower tpcb->tp_tpdusize > param->p_tpdusize) 28251996Ssklower tpcb->tp_tpdusize = param->p_tpdusize; 28351996Ssklower tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize; 28451996Ssklower } 28536406Ssklower } 28636406Ssklower done: 28736406Ssklower 28836406Ssklower IFTRACE(D_CONN) 28936406Ssklower tptrace(TPPTmisc, "tp_consist returns class xtdfmt cmd", 29036406Ssklower error, tpcb->tp_class, tpcb->tp_xtd_format, cmd); 29136406Ssklower ENDTRACE 29236406Ssklower IFDEBUG(D_CONN) 29336406Ssklower printf( 29436406Ssklower "tp_consist rtns 0x%x class 0x%x xtd_fmt 0x%x cmd 0x%x\n", 29536406Ssklower error, tpcb->tp_class, tpcb->tp_xtd_format, cmd); 29636406Ssklower ENDDEBUG 29736406Ssklower return error; 29836406Ssklower } 29936406Ssklower 30036406Ssklower /* 30136406Ssklower * NAME: tp_ctloutput() 30236406Ssklower * 30336406Ssklower * CALLED FROM: 30436406Ssklower * [sg]etsockopt(), via so[sg]etopt(). 30536406Ssklower * 30636406Ssklower * FUNCTION and ARGUMENTS: 30736406Ssklower * Implements the socket options at transport level. 30837536Smckusick * (cmd) is either PRCO_SETOPT or PRCO_GETOPT (see ../sys/protosw.h). 30936406Ssklower * (so) is the socket. 31037536Smckusick * (level) is SOL_TRANSPORT (see ../sys/socket.h) 31136406Ssklower * (optname) is the particular command or option to be set. 31236406Ssklower * (**mp) is an mbuf structure. 31336406Ssklower * 31436406Ssklower * RETURN VALUE: 31536406Ssklower * ENOTSOCK if the socket hasn't got an associated tpcb 31636406Ssklower * EINVAL if 31736406Ssklower * trying to set window too big 31836406Ssklower * trying to set illegal max tpdu size 31936406Ssklower * trying to set illegal credit fraction 32036406Ssklower * trying to use unknown or unimplemented class of TP 32136406Ssklower * structure passed to set timer values is wrong size 32236406Ssklower * illegal combination of command/GET-SET option, 32336406Ssklower * e.g., GET w/ TPOPT_CDDATA_CLEAR: 32436406Ssklower * EOPNOTSUPP if the level isn't transport, or command is neither GET nor SET 32536406Ssklower * or if the transport-specific command is not implemented 32636406Ssklower * EISCONN if trying a command that isn't allowed after a connection 32736406Ssklower * is established 32836406Ssklower * ENOTCONN if trying a command that is allowed only if a connection is 32936406Ssklower * established 33036406Ssklower * EMSGSIZE if trying to give too much data on connect/disconnect 33136406Ssklower * 33236406Ssklower * SIDE EFFECTS: 33336406Ssklower * 33436406Ssklower * NOTES: 33536406Ssklower */ 33636406Ssklower ProtoHook 33736406Ssklower tp_ctloutput(cmd, so, level, optname, mp) 33836406Ssklower int cmd, level, optname; 33936406Ssklower struct socket *so; 34036406Ssklower struct mbuf **mp; 34136406Ssklower { 34236406Ssklower struct tp_pcb *tpcb = sototpcb(so); 34336406Ssklower int s = splnet(); 34437469Ssklower caddr_t value; 34537469Ssklower unsigned val_len; 34636406Ssklower int error = 0; 34736406Ssklower 34836406Ssklower IFTRACE(D_REQUEST) 34936406Ssklower tptrace(TPPTmisc, "tp_ctloutput cmd so optname mp", 35036406Ssklower cmd, so, optname, mp); 35136406Ssklower ENDTRACE 35236406Ssklower IFDEBUG(D_REQUEST) 35336406Ssklower printf( 35436406Ssklower "tp_ctloutput so 0x%x cmd 0x%x optname 0x%x, mp 0x%x *mp 0x%x tpcb 0x%x\n", 35536406Ssklower so, cmd, optname, mp, mp?*mp:0, tpcb); 35636406Ssklower ENDDEBUG 35736406Ssklower if( tpcb == (struct tp_pcb *)0 ) { 35836406Ssklower error = ENOTSOCK; goto done; 35936406Ssklower } 36036406Ssklower if(*mp == MNULL) { 36136406Ssklower register struct mbuf *m; 36236406Ssklower 36336406Ssklower MGET(m, M_DONTWAIT, TPMT_SONAME); /* does off, type, next */ 36436406Ssklower if (m == NULL) { 36536406Ssklower splx(s); 36636406Ssklower return ENOBUFS; 36736406Ssklower } 36836406Ssklower m->m_len = 0; 36936406Ssklower m->m_act = 0; 37036406Ssklower *mp = m; 37136406Ssklower } 37236406Ssklower 37336406Ssklower /* 37436406Ssklower * Hook so one can set network options via a tp socket. 37536406Ssklower */ 37636406Ssklower if ( level == SOL_NETWORK ) { 37736406Ssklower if ((tpcb->tp_nlproto == NULL) || (tpcb->tp_npcb == NULL)) 37836406Ssklower error = ENOTSOCK; 37936406Ssklower else if (tpcb->tp_nlproto->nlp_ctloutput == NULL) 38036406Ssklower error = EOPNOTSUPP; 38136406Ssklower else 38250974Ssklower return ((tpcb->tp_nlproto->nlp_ctloutput)(cmd, optname, 38350974Ssklower tpcb->tp_npcb, *mp)); 38436406Ssklower goto done; 38550974Ssklower } else if ( level == SOL_SOCKET) { 38650974Ssklower if (optname == SO_RCVBUF && cmd == PRCO_SETOPT) { 387*53688Ssklower u_long old_credit = tpcb->tp_maxlcredit; 38850974Ssklower tp_rsyset(tpcb); 389*53688Ssklower if (tpcb->tp_rhiwat != so->so_rcv.sb_hiwat && 390*53688Ssklower tpcb->tp_state == TP_OPEN && 391*53688Ssklower (old_credit < tpcb->tp_maxlcredit)) 392*53688Ssklower tp_emit(AK_TPDU_type, tpcb, 393*53688Ssklower tpcb->tp_rcvnxt, 0, MNULL); 394*53688Ssklower tpcb->tp_rhiwat = so->so_rcv.sb_hiwat; 39550974Ssklower } 39650974Ssklower goto done; 39736406Ssklower } else if ( level != SOL_TRANSPORT ) { 39836406Ssklower error = EOPNOTSUPP; goto done; 39936406Ssklower } 40036406Ssklower if (cmd != PRCO_GETOPT && cmd != PRCO_SETOPT) { 40136406Ssklower error = EOPNOTSUPP; goto done; 40236406Ssklower } 40336406Ssklower if ( so->so_error ) { 40436406Ssklower error = so->so_error; goto done; 40536406Ssklower } 40636406Ssklower 40736406Ssklower /* The only options allowed after connection is established 40836406Ssklower * are GET (anything) and SET DISC DATA and SET PERF MEAS 40936406Ssklower */ 41036406Ssklower if ( ((so->so_state & SS_ISCONNECTING)||(so->so_state & SS_ISCONNECTED)) 41136406Ssklower && 41236406Ssklower (cmd == PRCO_SETOPT && 41336406Ssklower optname != TPOPT_DISC_DATA && 41438841Ssklower optname != TPOPT_CFRM_DATA && 41536406Ssklower optname != TPOPT_PERF_MEAS && 41636406Ssklower optname != TPOPT_CDDATA_CLEAR ) ) { 41736406Ssklower error = EISCONN; goto done; 41836406Ssklower } 41936406Ssklower /* The only options allowed after disconnection are GET DISC DATA, 42036406Ssklower * and TPOPT_PSTATISTICS 42136406Ssklower * and they're not allowed if the ref timer has gone off, because 42236406Ssklower * the tpcb is gone 42336406Ssklower */ 42438841Ssklower if ((so->so_state & (SS_ISCONNECTED | SS_ISCONFIRMING)) == 0) { 42550435Ssklower if ( so->so_pcb == (caddr_t)0 ) { 42636406Ssklower error = ENOTCONN; goto done; 42736406Ssklower } 42836406Ssklower if ( (tpcb->tp_state == TP_REFWAIT || tpcb->tp_state == TP_CLOSING) && 42936406Ssklower (optname != TPOPT_DISC_DATA && optname != TPOPT_PSTATISTICS)) { 43036406Ssklower error = ENOTCONN; goto done; 43136406Ssklower } 43236406Ssklower } 43336406Ssklower 43437469Ssklower value = mtod(*mp, caddr_t); /* it's aligned, don't worry, 43537469Ssklower * but lint complains about it 43637469Ssklower */ 43736406Ssklower val_len = (*mp)->m_len; 43836406Ssklower 43936406Ssklower switch (optname) { 44036406Ssklower 44144424Ssklower case TPOPT_INTERCEPT: 44250648Ssklower #define INA(t) (((struct inpcb *)(t->tp_npcb))->inp_laddr.s_addr) 44350648Ssklower #define ISOA(t) (((struct isopcb *)(t->tp_npcb))->isop_laddr->siso_addr) 44450648Ssklower 44550236Ssklower if ((so->so_state & SS_PRIV) == 0) { 44650236Ssklower error = EPERM; 44750648Ssklower } else if (cmd != PRCO_SETOPT || tpcb->tp_state != TP_CLOSED || 44850648Ssklower (tpcb->tp_flags & TPF_GENERAL_ADDR) || 44950648Ssklower tpcb->tp_next == 0) 45044424Ssklower error = EINVAL; 45144424Ssklower else { 45250648Ssklower register struct tp_pcb *t; 45350648Ssklower error = EADDRINUSE; 45450648Ssklower for (t = tp_listeners; t; t = t->tp_nextlisten) 45550648Ssklower if ((t->tp_flags & TPF_GENERAL_ADDR) == 0 && 45650648Ssklower t->tp_domain == tpcb->tp_domain) 45750648Ssklower switch (tpcb->tp_domain) { 45850648Ssklower default: 45950648Ssklower goto done; 46050648Ssklower #ifdef INET 46150648Ssklower case AF_INET: 46250648Ssklower if (INA(t) == INA(tpcb)) 46350648Ssklower goto done; 46450648Ssklower continue; 46550648Ssklower #endif 46650648Ssklower #ifdef ISO 46750648Ssklower case AF_ISO: 46850648Ssklower if (bcmp(ISOA(t).isoa_genaddr, ISOA(tpcb).isoa_genaddr, 46950648Ssklower ISOA(t).isoa_len) == 0) 47050648Ssklower goto done; 47150648Ssklower continue; 47250648Ssklower #endif 47350648Ssklower } 47450648Ssklower tpcb->tp_lsuffixlen = 0; 47550648Ssklower tpcb->tp_state = TP_LISTENING; 47650648Ssklower error = 0; 47750648Ssklower remque(tpcb); 47850648Ssklower tpcb->tp_next = tpcb->tp_prev = tpcb; 47950648Ssklower tpcb->tp_nextlisten = tp_listeners; 48050648Ssklower tp_listeners = tpcb; 48144424Ssklower } 48244424Ssklower break; 48344424Ssklower 48436406Ssklower case TPOPT_MY_TSEL: 48536406Ssklower if ( cmd == PRCO_GETOPT ) { 48636406Ssklower ASSERT( tpcb->tp_lsuffixlen <= MAX_TSAP_SEL_LEN ); 48737469Ssklower bcopy((caddr_t)tpcb->tp_lsuffix, value, tpcb->tp_lsuffixlen); 48836406Ssklower (*mp)->m_len = tpcb->tp_lsuffixlen; 48936406Ssklower } else /* cmd == PRCO_SETOPT */ { 49036406Ssklower if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { 49136406Ssklower printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); 49236406Ssklower error = EINVAL; 49336406Ssklower } else { 49437469Ssklower bcopy(value, (caddr_t)tpcb->tp_lsuffix, val_len); 49536406Ssklower tpcb->tp_lsuffixlen = val_len; 49636406Ssklower } 49736406Ssklower } 49836406Ssklower break; 49936406Ssklower 50036406Ssklower case TPOPT_PEER_TSEL: 50136406Ssklower if ( cmd == PRCO_GETOPT ) { 50236406Ssklower ASSERT( tpcb->tp_fsuffixlen <= MAX_TSAP_SEL_LEN ); 50337469Ssklower bcopy((caddr_t)tpcb->tp_fsuffix, value, tpcb->tp_fsuffixlen); 50436406Ssklower (*mp)->m_len = tpcb->tp_fsuffixlen; 50536406Ssklower } else /* cmd == PRCO_SETOPT */ { 50636406Ssklower if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { 50736406Ssklower printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); 50836406Ssklower error = EINVAL; 50936406Ssklower } else { 51037469Ssklower bcopy(value, (caddr_t)tpcb->tp_fsuffix, val_len); 51136406Ssklower tpcb->tp_fsuffixlen = val_len; 51236406Ssklower } 51336406Ssklower } 51436406Ssklower break; 51536406Ssklower 51636406Ssklower case TPOPT_FLAGS: 51736406Ssklower IFDEBUG(D_REQUEST) 51836406Ssklower printf("%s TPOPT_FLAGS value 0x%x *value 0x%x, flags 0x%x \n", 51936406Ssklower cmd==PRCO_GETOPT?"GET":"SET", 52036406Ssklower value, 52136406Ssklower *value, 52236406Ssklower tpcb->tp_flags); 52336406Ssklower ENDDEBUG 52436406Ssklower 52536406Ssklower if ( cmd == PRCO_GETOPT ) { 52636406Ssklower *(int *)value = (int)tpcb->tp_flags; 52736406Ssklower (*mp)->m_len = sizeof(u_int); 52836406Ssklower } else /* cmd == PRCO_SETOPT */ { 52936406Ssklower error = EINVAL; goto done; 53036406Ssklower } 53136406Ssklower break; 53236406Ssklower 53336406Ssklower case TPOPT_PARAMS: 53436406Ssklower /* This handles: 53536406Ssklower * timer values, 53636406Ssklower * class, use of transport expedited data, 53736406Ssklower * max tpdu size, checksum, xtd format and 53836406Ssklower * disconnect indications, and may get rid of connect/disc data 53936406Ssklower */ 54036406Ssklower IFDEBUG(D_SETPARAMS) 54136406Ssklower printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, 54236406Ssklower cmd==PRCO_GETOPT?"GET":"SET"); 54336406Ssklower ENDDEBUG 54436406Ssklower IFDEBUG(D_REQUEST) 54536406Ssklower printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, 54636406Ssklower cmd==PRCO_GETOPT?"GET":"SET"); 54736406Ssklower ENDDEBUG 54836406Ssklower 54936406Ssklower if ( cmd == PRCO_GETOPT ) { 55036406Ssklower *(struct tp_conn_param *)value = tpcb->_tp_param; 55136406Ssklower (*mp)->m_len = sizeof(tpcb->_tp_param); 55236406Ssklower } else /* cmd == PRCO_SETOPT */ { 55336406Ssklower if( (error = 55436406Ssklower tp_consistency(tpcb, TP_STRICT | TP_FORCE, 55536406Ssklower (struct tp_conn_param *)value))==0) { 55636406Ssklower /* 55736406Ssklower * tp_consistency doesn't copy the whole set of params 55836406Ssklower */ 55936406Ssklower tpcb->_tp_param = *(struct tp_conn_param *)value; 56036406Ssklower (*mp)->m_len = sizeof(tpcb->_tp_param); 56136406Ssklower } 56236406Ssklower } 56336406Ssklower break; 56436406Ssklower 56536406Ssklower case TPOPT_PSTATISTICS: 56636406Ssklower #ifdef TP_PERF_MEAS 56736406Ssklower if (cmd == PRCO_SETOPT) { 56836406Ssklower error = EINVAL; goto done; 56936406Ssklower } 57036406Ssklower IFPERF(tpcb) 57137469Ssklower if (*mp) { 57237469Ssklower struct mbuf * n; 57337469Ssklower do { 57437469Ssklower MFREE(*mp, n); 57537469Ssklower *mp = n; 57637469Ssklower } while (n); 57737469Ssklower } 57837469Ssklower *mp = m_copym(tpcb->tp_p_mbuf, (int)M_COPYALL, M_WAITOK); 57936406Ssklower ENDPERF 58036406Ssklower else { 58136406Ssklower error = EINVAL; goto done; 58236406Ssklower } 58336406Ssklower break; 58436406Ssklower #else 58536406Ssklower error = EOPNOTSUPP; 58636406Ssklower goto done; 58736406Ssklower #endif TP_PERF_MEAS 58836406Ssklower 58936406Ssklower case TPOPT_CDDATA_CLEAR: 59036406Ssklower if (cmd == PRCO_GETOPT) { 59136406Ssklower error = EINVAL; 59236406Ssklower } else { 59337469Ssklower if (tpcb->tp_ucddata) { 59438841Ssklower m_freem(tpcb->tp_ucddata); 59538841Ssklower tpcb->tp_ucddata = 0; 59636406Ssklower } 59736406Ssklower } 59836406Ssklower break; 59936406Ssklower 60038841Ssklower case TPOPT_CFRM_DATA: 60136406Ssklower case TPOPT_DISC_DATA: 60236406Ssklower case TPOPT_CONN_DATA: 60336406Ssklower if( tpcb->tp_class == TP_CLASS_0 ) { 60436406Ssklower error = EOPNOTSUPP; 60536406Ssklower break; 60636406Ssklower } 60736406Ssklower IFDEBUG(D_REQUEST) 60836406Ssklower printf("%s\n", optname==TPOPT_DISC_DATA?"DISC data":"CONN data"); 60936406Ssklower printf("m_len 0x%x, vallen 0x%x so_snd.cc 0x%x\n", 61036406Ssklower (*mp)->m_len, val_len, so->so_snd.sb_cc); 61136406Ssklower dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput: sosnd "); 61236406Ssklower ENDDEBUG 61336406Ssklower if (cmd == PRCO_SETOPT) { 61437469Ssklower int len = tpcb->tp_ucddata ? tpcb->tp_ucddata->m_len : 0; 61536406Ssklower /* can append connect data in several calls */ 61637469Ssklower if (len + val_len > 61736406Ssklower (optname==TPOPT_CONN_DATA?TP_MAX_CR_DATA:TP_MAX_DR_DATA) ) { 61836406Ssklower error = EMSGSIZE; goto done; 61936406Ssklower } 62036406Ssklower (*mp)->m_next = MNULL; 62136406Ssklower (*mp)->m_act = 0; 62237469Ssklower if (tpcb->tp_ucddata) 62337469Ssklower m_cat(tpcb->tp_ucddata, *mp); 62437469Ssklower else 62537469Ssklower tpcb->tp_ucddata = *mp; 62640241Ssklower IFDEBUG(D_REQUEST) 62740241Ssklower dump_mbuf(tpcb->tp_ucddata, "tp_ctloutput after CONN_DATA"); 62840241Ssklower ENDDEBUG 62936406Ssklower IFTRACE(D_REQUEST) 63036406Ssklower tptrace(TPPTmisc,"C/D DATA: flags snd.sbcc val_len", 63136406Ssklower tpcb->tp_flags, so->so_snd.sb_cc,val_len,0); 63236406Ssklower ENDTRACE 63350974Ssklower *mp = MNULL; 63440241Ssklower if (optname == TPOPT_CFRM_DATA && (so->so_state & SS_ISCONFIRMING)) 63540241Ssklower (void) tp_confirm(tpcb); 63636406Ssklower } 63736406Ssklower break; 63836406Ssklower 63936406Ssklower case TPOPT_PERF_MEAS: 64036406Ssklower #ifdef TP_PERF_MEAS 64136406Ssklower if (cmd == PRCO_GETOPT) { 64236406Ssklower *value = (u_int)tpcb->tp_perf_on; 64336406Ssklower (*mp)->m_len = sizeof(u_int); 64436406Ssklower } else if (cmd == PRCO_SETOPT) { 64536406Ssklower (*mp)->m_len = 0; 64636406Ssklower if ((*value) != 0 && (*value) != 1 ) 64736406Ssklower error = EINVAL; 64836406Ssklower else tpcb->tp_perf_on = (*value); 64936406Ssklower } 65036406Ssklower if( tpcb->tp_perf_on ) 65136406Ssklower error = tp_setup_perf(tpcb); 65236406Ssklower #else TP_PERF_MEAS 65336406Ssklower error = EOPNOTSUPP; 65436406Ssklower #endif TP_PERF_MEAS 65536406Ssklower break; 65636406Ssklower 65736406Ssklower default: 65836406Ssklower error = EOPNOTSUPP; 65936406Ssklower } 66036406Ssklower 66136406Ssklower done: 66236406Ssklower IFDEBUG(D_REQUEST) 66336406Ssklower dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput sosnd at end"); 66436406Ssklower dump_mbuf(*mp, "tp_ctloutput *mp"); 66536406Ssklower ENDDEBUG 66636406Ssklower /* 66736406Ssklower * sigh: getsockopt looks only at m_len : all output data must 66836406Ssklower * reside in the first mbuf 66936406Ssklower */ 67050974Ssklower if (*mp) { 671*53688Ssklower if (cmd == PRCO_SETOPT) { 67250974Ssklower m_freem(*mp); 673*53688Ssklower *mp = MNULL; 674*53688Ssklower } else { 67550974Ssklower ASSERT ( m_compress(*mp, mp) <= MLEN ); 67650974Ssklower if (error) 67750974Ssklower (*mp)->m_len = 0; 67850974Ssklower IFDEBUG(D_REQUEST) 67950974Ssklower dump_mbuf(*mp, "tp_ctloutput *mp after compress"); 68050974Ssklower ENDDEBUG 68150974Ssklower } 68236406Ssklower } 68336406Ssklower splx(s); 68436406Ssklower return error; 68536406Ssklower } 686