1*36406Ssklower /*********************************************************** 2*36406Ssklower Copyright IBM Corporation 1987 3*36406Ssklower 4*36406Ssklower All Rights Reserved 5*36406Ssklower 6*36406Ssklower Permission to use, copy, modify, and distribute this software and its 7*36406Ssklower documentation for any purpose and without fee is hereby granted, 8*36406Ssklower provided that the above copyright notice appear in all copies and that 9*36406Ssklower both that copyright notice and this permission notice appear in 10*36406Ssklower supporting documentation, and that the name of IBM not be 11*36406Ssklower used in advertising or publicity pertaining to distribution of the 12*36406Ssklower software without specific, written prior permission. 13*36406Ssklower 14*36406Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 15*36406Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 16*36406Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 17*36406Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 18*36406Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 19*36406Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20*36406Ssklower SOFTWARE. 21*36406Ssklower 22*36406Ssklower ******************************************************************/ 23*36406Ssklower 24*36406Ssklower /* 25*36406Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 26*36406Ssklower */ 27*36406Ssklower /* 28*36406Ssklower * ARGO TP 29*36406Ssklower * 30*36406Ssklower * $Header: tp_output.c,v 5.4 88/11/18 17:28:08 nhall Exp $ 31*36406Ssklower * $Source: /usr/argo/sys/netiso/RCS/tp_output.c,v $ 32*36406Ssklower * 33*36406Ssklower * In here is tp_ctloutput(), the guy called by [sg]etsockopt(), 34*36406Ssklower */ 35*36406Ssklower 36*36406Ssklower #ifndef lint 37*36406Ssklower static char *rcsid = "$Header: tp_output.c,v 5.4 88/11/18 17:28:08 nhall Exp $"; 38*36406Ssklower #endif lint 39*36406Ssklower 40*36406Ssklower #include "param.h" 41*36406Ssklower #include "systm.h" 42*36406Ssklower #include "mbuf.h" 43*36406Ssklower #include "protosw.h" 44*36406Ssklower #include "socket.h" 45*36406Ssklower #include "socketvar.h" 46*36406Ssklower #include "errno.h" 47*36406Ssklower #include "types.h" 48*36406Ssklower #include "time.h" 49*36406Ssklower #include "../netiso/tp_param.h" 50*36406Ssklower #include "../netiso/tp_user.h" 51*36406Ssklower #include "../netiso/tp_stat.h" 52*36406Ssklower #include "../netiso/tp_ip.h" 53*36406Ssklower #include "../netiso/tp_timer.h" 54*36406Ssklower #include "../netiso/argo_debug.h" 55*36406Ssklower #include "../netiso/tp_pcb.h" 56*36406Ssklower #include "../netiso/tp_trace.h" 57*36406Ssklower 58*36406Ssklower #define USERFLAGSMASK_G 0x0f00643b 59*36406Ssklower #define USERFLAGSMASK_S 0x0f000432 60*36406Ssklower #define TPDUSIZESHIFT 24 61*36406Ssklower #define CLASSHIFT 16 62*36406Ssklower 63*36406Ssklower /* 64*36406Ssklower * NAME: tp_consistency() 65*36406Ssklower * 66*36406Ssklower * CALLED FROM: 67*36406Ssklower * tp_ctloutput(), tp_input() 68*36406Ssklower * 69*36406Ssklower * FUNCTION and ARGUMENTS: 70*36406Ssklower * Checks the consistency of options and tpdusize with class, 71*36406Ssklower * using the parameters passed in via (param). 72*36406Ssklower * (cmd) may be TP_STRICT or TP_FORCE or both. 73*36406Ssklower * Force means it will set all the values in (tpcb) to those in 74*36406Ssklower * the input arguements iff no errors were encountered. 75*36406Ssklower * Strict means that no inconsistency will be tolerated. If it's 76*36406Ssklower * not used, checksum and tpdusize inconsistencies will be tolerated. 77*36406Ssklower * The reason for this is that in some cases, when we're negotiating down 78*36406Ssklower * from class 4, these options should be changed but should not 79*36406Ssklower * cause negotiation to fail. 80*36406Ssklower * 81*36406Ssklower * RETURNS 82*36406Ssklower * E* or EOK 83*36406Ssklower * E* if the various parms aren't ok for a given class 84*36406Ssklower * EOK if they are ok for a given class 85*36406Ssklower */ 86*36406Ssklower 87*36406Ssklower int 88*36406Ssklower tp_consistency( tpcb, cmd, param ) 89*36406Ssklower u_int cmd; 90*36406Ssklower struct tp_conn_param *param; 91*36406Ssklower struct tp_pcb *tpcb; 92*36406Ssklower { 93*36406Ssklower register int error = EOK; 94*36406Ssklower int class_to_use = tp_mask_to_num(param->p_class); 95*36406Ssklower 96*36406Ssklower IFTRACE(D_SETPARAMS) 97*36406Ssklower tptrace(TPPTmisc, 98*36406Ssklower "tp_consist enter class_to_use dontchange param.class cmd", 99*36406Ssklower class_to_use, param->p_dont_change_params, param->p_class, cmd); 100*36406Ssklower ENDTRACE 101*36406Ssklower IFDEBUG(D_SETPARAMS) 102*36406Ssklower printf("tp_consistency %s %s\n", 103*36406Ssklower cmd& TP_FORCE? "TP_FORCE": "", 104*36406Ssklower cmd& TP_STRICT? "TP_STRICT":""); 105*36406Ssklower ENDDEBUG 106*36406Ssklower if ((cmd & TP_FORCE) && (param->p_dont_change_params)) { 107*36406Ssklower cmd &= ~TP_FORCE; 108*36406Ssklower } 109*36406Ssklower /* can switch net services within a domain, but 110*36406Ssklower * cannot switch domains 111*36406Ssklower */ 112*36406Ssklower switch( param->p_netservice) { 113*36406Ssklower case ISO_CONS: 114*36406Ssklower case ISO_CLNS: 115*36406Ssklower case ISO_COSNS: 116*36406Ssklower /* param->p_netservice in ISO DOMAIN */ 117*36406Ssklower if(tpcb->tp_domain != AF_ISO ) { 118*36406Ssklower error = EINVAL; goto done; 119*36406Ssklower } 120*36406Ssklower break; 121*36406Ssklower case IN_CLNS: 122*36406Ssklower /* param->p_netservice in INET DOMAIN */ 123*36406Ssklower if( tpcb->tp_domain != AF_INET ) { 124*36406Ssklower error = EINVAL; goto done; 125*36406Ssklower } 126*36406Ssklower break; 127*36406Ssklower /* no others not possible-> netservice is a 2-bit field! */ 128*36406Ssklower } 129*36406Ssklower 130*36406Ssklower IFDEBUG(D_SETPARAMS) 131*36406Ssklower printf("p_class 0x%x, class_to_use 0x%x\n", param->p_class, 132*36406Ssklower class_to_use); 133*36406Ssklower ENDDEBUG 134*36406Ssklower if((param->p_netservice < 0) || (param->p_netservice > TP_MAX_NETSERVICES)){ 135*36406Ssklower error = EINVAL; goto done; 136*36406Ssklower } 137*36406Ssklower if( (param->p_class & TP_CLASSES_IMPLEMENTED) == 0 ) { 138*36406Ssklower error = EINVAL; goto done; 139*36406Ssklower } 140*36406Ssklower IFDEBUG(D_SETPARAMS) 141*36406Ssklower printf("Nretrans 0x%x\n", param->p_Nretrans ); 142*36406Ssklower ENDDEBUG 143*36406Ssklower if( ( param->p_Nretrans < 1 ) || 144*36406Ssklower (param->p_cr_ticks < 1) || (param->p_cc_ticks < 1) ) { 145*36406Ssklower /* bad for any class because negot has to be done a la class 4 */ 146*36406Ssklower error = EINVAL; goto done; 147*36406Ssklower } 148*36406Ssklower IFDEBUG(D_SETPARAMS) 149*36406Ssklower printf("winsize 0x%x\n", param->p_winsize ); 150*36406Ssklower ENDDEBUG 151*36406Ssklower if( (param->p_winsize < 128 ) || 152*36406Ssklower (param->p_winsize < param->p_tpdusize ) || 153*36406Ssklower (param->p_winsize > ((1+SB_MAX)>>2 /* 1/4 of the max */)) ) { 154*36406Ssklower error = EINVAL; goto done; 155*36406Ssklower } else { 156*36406Ssklower if( tpcb->tp_state == TP_CLOSED ) 157*36406Ssklower soreserve(tpcb->tp_sock, param->p_winsize, param->p_winsize); 158*36406Ssklower } 159*36406Ssklower IFDEBUG(D_SETPARAMS) 160*36406Ssklower printf("use_csum 0x%x\n", param->p_use_checksum ); 161*36406Ssklower printf("xtd_format 0x%x\n", param->p_xtd_format ); 162*36406Ssklower printf("xpd_service 0x%x\n", param->p_xpd_service ); 163*36406Ssklower printf("tpdusize 0x%x\n", param->p_tpdusize ); 164*36406Ssklower printf("tpcb->flags 0x%x\n", tpcb->tp_flags ); 165*36406Ssklower ENDDEBUG 166*36406Ssklower switch( class_to_use ) { 167*36406Ssklower 168*36406Ssklower case 0: 169*36406Ssklower /* do not use checksums, xtd format, or XPD */ 170*36406Ssklower 171*36406Ssklower if( param->p_use_checksum | param->p_xtd_format | param->p_xpd_service ) { 172*36406Ssklower if(cmd & TP_STRICT) { 173*36406Ssklower error = EINVAL; 174*36406Ssklower } else { 175*36406Ssklower param->p_use_checksum = 0; 176*36406Ssklower param->p_xtd_format = 0; 177*36406Ssklower param->p_xpd_service = 0; 178*36406Ssklower } 179*36406Ssklower break; 180*36406Ssklower } 181*36406Ssklower 182*36406Ssklower if (param->p_tpdusize < TP_MIN_TPDUSIZE) { 183*36406Ssklower if(cmd & TP_STRICT) { 184*36406Ssklower error = EINVAL; 185*36406Ssklower } else { 186*36406Ssklower param->p_tpdusize = TP_MIN_TPDUSIZE; 187*36406Ssklower } 188*36406Ssklower break; 189*36406Ssklower } 190*36406Ssklower if (param->p_tpdusize > TP0_TPDUSIZE) { 191*36406Ssklower if (cmd & TP_STRICT) { 192*36406Ssklower error = EINVAL; 193*36406Ssklower } else { 194*36406Ssklower param->p_tpdusize = TP0_TPDUSIZE; 195*36406Ssklower } 196*36406Ssklower break; 197*36406Ssklower } 198*36406Ssklower 199*36406Ssklower /* connect/disc data not allowed for class 0 */ 200*36406Ssklower if ( tpcb->tp_flags & 201*36406Ssklower (TPF_CONN_DATA_OUT | TPF_DISC_DATA_OUT) ) { 202*36406Ssklower if(cmd & TP_STRICT) { 203*36406Ssklower error = EINVAL; 204*36406Ssklower } else if(cmd & TP_FORCE) { 205*36406Ssklower sbdrop(&tpcb->tp_sock->so_snd, tpcb->tp_sock->so_snd.sb_cc); 206*36406Ssklower tpcb->tp_flags &= 207*36406Ssklower ~(TPF_CONN_DATA_OUT | TPF_DISC_DATA_OUT); 208*36406Ssklower } 209*36406Ssklower } 210*36406Ssklower break; 211*36406Ssklower 212*36406Ssklower case 4: 213*36406Ssklower IFDEBUG(D_SETPARAMS) 214*36406Ssklower printf("dt_ticks 0x%x\n", param->p_dt_ticks ); 215*36406Ssklower printf("x_ticks 0x%x\n", param->p_x_ticks ); 216*36406Ssklower printf("dr_ticks 0x%x\n", param->p_dr_ticks ); 217*36406Ssklower printf("keepalive 0x%x\n", param->p_keepalive_ticks ); 218*36406Ssklower printf("sendack 0x%x\n", param->p_sendack_ticks ); 219*36406Ssklower printf("inact 0x%x\n", param->p_inact_ticks ); 220*36406Ssklower printf("ref 0x%x\n", param->p_ref_ticks ); 221*36406Ssklower ENDDEBUG 222*36406Ssklower if( (param->p_class & TP_CLASS_4 ) && ( 223*36406Ssklower (param->p_dt_ticks < 1) || (param->p_dr_ticks < 1) || 224*36406Ssklower (param->p_x_ticks < 1) || (param->p_keepalive_ticks < 1) || 225*36406Ssklower (param->p_sendack_ticks < 1) || (param->p_ref_ticks < 1) || 226*36406Ssklower (param->p_inact_ticks < 1) ) ) { 227*36406Ssklower error = EINVAL; 228*36406Ssklower break; 229*36406Ssklower } 230*36406Ssklower IFDEBUG(D_SETPARAMS) 231*36406Ssklower printf("rx_strat 0x%x\n", param->p_rx_strat ); 232*36406Ssklower ENDDEBUG 233*36406Ssklower if(param->p_rx_strat > 234*36406Ssklower ( TPRX_USE_CW | TPRX_EACH | TPRX_FASTSTART) ) { 235*36406Ssklower if(cmd & TP_STRICT) { 236*36406Ssklower error = EINVAL; 237*36406Ssklower } else { 238*36406Ssklower param->p_rx_strat = TPRX_USE_CW; 239*36406Ssklower } 240*36406Ssklower break; 241*36406Ssklower } 242*36406Ssklower IFDEBUG(D_SETPARAMS) 243*36406Ssklower printf("ack_strat 0x%x\n", param->p_ack_strat ); 244*36406Ssklower ENDDEBUG 245*36406Ssklower if((param->p_ack_strat != 0) && (param->p_ack_strat != 1)) { 246*36406Ssklower if(cmd & TP_STRICT) { 247*36406Ssklower error = EINVAL; 248*36406Ssklower } else { 249*36406Ssklower param->p_ack_strat = TPACK_WINDOW; 250*36406Ssklower } 251*36406Ssklower break; 252*36406Ssklower } 253*36406Ssklower if (param->p_tpdusize < TP_MIN_TPDUSIZE) { 254*36406Ssklower if(cmd & TP_STRICT) { 255*36406Ssklower error = EINVAL; 256*36406Ssklower } else { 257*36406Ssklower param->p_tpdusize = TP_MIN_TPDUSIZE; 258*36406Ssklower } 259*36406Ssklower break; 260*36406Ssklower } 261*36406Ssklower if (param->p_tpdusize > TP_TPDUSIZE) { 262*36406Ssklower if(cmd & TP_STRICT) { 263*36406Ssklower error = EINVAL; 264*36406Ssklower } else { 265*36406Ssklower param->p_tpdusize = TP_TPDUSIZE; 266*36406Ssklower } 267*36406Ssklower break; 268*36406Ssklower } 269*36406Ssklower break; 270*36406Ssklower } 271*36406Ssklower 272*36406Ssklower if ((error==0) && (cmd & TP_FORCE)) { 273*36406Ssklower tpcb->tp_tpdusize = param->p_tpdusize; 274*36406Ssklower tpcb->tp_class = param->p_class; 275*36406Ssklower tpcb->tp_use_checksum = param->p_use_checksum; 276*36406Ssklower tpcb->tp_xpd_service = param->p_xpd_service; 277*36406Ssklower tpcb->tp_xtd_format = param->p_xtd_format; 278*36406Ssklower } 279*36406Ssklower 280*36406Ssklower done: 281*36406Ssklower 282*36406Ssklower IFTRACE(D_CONN) 283*36406Ssklower tptrace(TPPTmisc, "tp_consist returns class xtdfmt cmd", 284*36406Ssklower error, tpcb->tp_class, tpcb->tp_xtd_format, cmd); 285*36406Ssklower ENDTRACE 286*36406Ssklower IFDEBUG(D_CONN) 287*36406Ssklower printf( 288*36406Ssklower "tp_consist rtns 0x%x class 0x%x xtd_fmt 0x%x cmd 0x%x\n", 289*36406Ssklower error, tpcb->tp_class, tpcb->tp_xtd_format, cmd); 290*36406Ssklower ENDDEBUG 291*36406Ssklower return error; 292*36406Ssklower } 293*36406Ssklower 294*36406Ssklower /* 295*36406Ssklower * NAME: tp_ctloutput() 296*36406Ssklower * 297*36406Ssklower * CALLED FROM: 298*36406Ssklower * [sg]etsockopt(), via so[sg]etopt(). 299*36406Ssklower * 300*36406Ssklower * FUNCTION and ARGUMENTS: 301*36406Ssklower * Implements the socket options at transport level. 302*36406Ssklower * (cmd) is either PRCO_SETOPT or PRCO_GETOPT (see ../h/protosw.h). 303*36406Ssklower * (so) is the socket. 304*36406Ssklower * (level) is SOL_TRANSPORT (see ../h/socket.h) 305*36406Ssklower * (optname) is the particular command or option to be set. 306*36406Ssklower * (**mp) is an mbuf structure. 307*36406Ssklower * 308*36406Ssklower * RETURN VALUE: 309*36406Ssklower * ENOTSOCK if the socket hasn't got an associated tpcb 310*36406Ssklower * EINVAL if 311*36406Ssklower * trying to set window too big 312*36406Ssklower * trying to set illegal max tpdu size 313*36406Ssklower * trying to set illegal credit fraction 314*36406Ssklower * trying to use unknown or unimplemented class of TP 315*36406Ssklower * structure passed to set timer values is wrong size 316*36406Ssklower * illegal combination of command/GET-SET option, 317*36406Ssklower * e.g., GET w/ TPOPT_CDDATA_CLEAR: 318*36406Ssklower * EOPNOTSUPP if the level isn't transport, or command is neither GET nor SET 319*36406Ssklower * or if the transport-specific command is not implemented 320*36406Ssklower * EISCONN if trying a command that isn't allowed after a connection 321*36406Ssklower * is established 322*36406Ssklower * ENOTCONN if trying a command that is allowed only if a connection is 323*36406Ssklower * established 324*36406Ssklower * EMSGSIZE if trying to give too much data on connect/disconnect 325*36406Ssklower * 326*36406Ssklower * SIDE EFFECTS: 327*36406Ssklower * 328*36406Ssklower * NOTES: 329*36406Ssklower */ 330*36406Ssklower ProtoHook 331*36406Ssklower tp_ctloutput(cmd, so, level, optname, mp) 332*36406Ssklower int cmd, level, optname; 333*36406Ssklower struct socket *so; 334*36406Ssklower struct mbuf **mp; 335*36406Ssklower { 336*36406Ssklower struct tp_pcb *tpcb = sototpcb(so); 337*36406Ssklower int s = splnet(); 338*36406Ssklower u_char *value; 339*36406Ssklower int val_len; 340*36406Ssklower int error = 0; 341*36406Ssklower 342*36406Ssklower IFTRACE(D_REQUEST) 343*36406Ssklower tptrace(TPPTmisc, "tp_ctloutput cmd so optname mp", 344*36406Ssklower cmd, so, optname, mp); 345*36406Ssklower ENDTRACE 346*36406Ssklower IFDEBUG(D_REQUEST) 347*36406Ssklower printf( 348*36406Ssklower "tp_ctloutput so 0x%x cmd 0x%x optname 0x%x, mp 0x%x *mp 0x%x tpcb 0x%x\n", 349*36406Ssklower so, cmd, optname, mp, mp?*mp:0, tpcb); 350*36406Ssklower ENDDEBUG 351*36406Ssklower if( tpcb == (struct tp_pcb *)0 ) { 352*36406Ssklower error = ENOTSOCK; goto done; 353*36406Ssklower } 354*36406Ssklower if(*mp == MNULL) { 355*36406Ssklower register struct mbuf *m; 356*36406Ssklower 357*36406Ssklower MGET(m, M_DONTWAIT, TPMT_SONAME); /* does off, type, next */ 358*36406Ssklower if (m == NULL) { 359*36406Ssklower splx(s); 360*36406Ssklower return ENOBUFS; 361*36406Ssklower } 362*36406Ssklower m->m_len = 0; 363*36406Ssklower m->m_act = 0; 364*36406Ssklower *mp = m; 365*36406Ssklower } 366*36406Ssklower 367*36406Ssklower /* 368*36406Ssklower * Hook so one can set network options via a tp socket. 369*36406Ssklower */ 370*36406Ssklower if ( level == SOL_NETWORK ) { 371*36406Ssklower if ((tpcb->tp_nlproto == NULL) || (tpcb->tp_npcb == NULL)) 372*36406Ssklower error = ENOTSOCK; 373*36406Ssklower else if (tpcb->tp_nlproto->nlp_ctloutput == NULL) 374*36406Ssklower error = EOPNOTSUPP; 375*36406Ssklower else 376*36406Ssklower error = (tpcb->tp_nlproto->nlp_ctloutput)(cmd, optname, 377*36406Ssklower tpcb->tp_npcb, *mp); 378*36406Ssklower goto done; 379*36406Ssklower } else if ( level != SOL_TRANSPORT ) { 380*36406Ssklower error = EOPNOTSUPP; goto done; 381*36406Ssklower } 382*36406Ssklower if (cmd != PRCO_GETOPT && cmd != PRCO_SETOPT) { 383*36406Ssklower error = EOPNOTSUPP; goto done; 384*36406Ssklower } 385*36406Ssklower if ( so->so_error ) { 386*36406Ssklower error = so->so_error; goto done; 387*36406Ssklower } 388*36406Ssklower 389*36406Ssklower /* The only options allowed after connection is established 390*36406Ssklower * are GET (anything) and SET DISC DATA and SET PERF MEAS 391*36406Ssklower */ 392*36406Ssklower if ( ((so->so_state & SS_ISCONNECTING)||(so->so_state & SS_ISCONNECTED)) 393*36406Ssklower && 394*36406Ssklower (cmd == PRCO_SETOPT && 395*36406Ssklower optname != TPOPT_DISC_DATA && 396*36406Ssklower optname != TPOPT_PERF_MEAS && 397*36406Ssklower optname != TPOPT_CDDATA_CLEAR ) ) { 398*36406Ssklower error = EISCONN; goto done; 399*36406Ssklower } 400*36406Ssklower /* The only options allowed after disconnection are GET DISC DATA, 401*36406Ssklower * and TPOPT_PSTATISTICS 402*36406Ssklower * and they're not allowed if the ref timer has gone off, because 403*36406Ssklower * the tpcb is gone 404*36406Ssklower */ 405*36406Ssklower if ((so->so_state & SS_ISCONNECTED) == 0) { 406*36406Ssklower if ( so->so_tpcb == (caddr_t)0 ) { 407*36406Ssklower error = ENOTCONN; goto done; 408*36406Ssklower } 409*36406Ssklower if ( (tpcb->tp_state == TP_REFWAIT || tpcb->tp_state == TP_CLOSING) && 410*36406Ssklower (optname != TPOPT_DISC_DATA && optname != TPOPT_PSTATISTICS)) { 411*36406Ssklower error = ENOTCONN; goto done; 412*36406Ssklower } 413*36406Ssklower } 414*36406Ssklower 415*36406Ssklower value = (u_char *) mtod(*mp, u_char *); /* it's aligned, don't worry, 416*36406Ssklower * but lint complains about it 417*36406Ssklower */ 418*36406Ssklower val_len = (*mp)->m_len; 419*36406Ssklower 420*36406Ssklower switch (optname) { 421*36406Ssklower 422*36406Ssklower case TPOPT_MY_TSEL: 423*36406Ssklower if ( cmd == PRCO_GETOPT ) { 424*36406Ssklower ASSERT( tpcb->tp_lsuffixlen <= MAX_TSAP_SEL_LEN ); 425*36406Ssklower bcopy( tpcb->tp_lsuffix, value, tpcb->tp_lsuffixlen); 426*36406Ssklower (*mp)->m_len = tpcb->tp_lsuffixlen; 427*36406Ssklower } else /* cmd == PRCO_SETOPT */ { 428*36406Ssklower if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { 429*36406Ssklower printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); 430*36406Ssklower error = EINVAL; 431*36406Ssklower } else { 432*36406Ssklower bcopy( value, tpcb->tp_lsuffix, val_len ); 433*36406Ssklower tpcb->tp_lsuffixlen = val_len; 434*36406Ssklower } 435*36406Ssklower } 436*36406Ssklower break; 437*36406Ssklower 438*36406Ssklower case TPOPT_PEER_TSEL: 439*36406Ssklower if ( cmd == PRCO_GETOPT ) { 440*36406Ssklower ASSERT( tpcb->tp_fsuffixlen <= MAX_TSAP_SEL_LEN ); 441*36406Ssklower bcopy( tpcb->tp_fsuffix, value, tpcb->tp_fsuffixlen); 442*36406Ssklower (*mp)->m_len = tpcb->tp_fsuffixlen; 443*36406Ssklower } else /* cmd == PRCO_SETOPT */ { 444*36406Ssklower if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { 445*36406Ssklower printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); 446*36406Ssklower error = EINVAL; 447*36406Ssklower } else { 448*36406Ssklower bcopy( value, tpcb->tp_fsuffix, val_len ); 449*36406Ssklower tpcb->tp_fsuffixlen = val_len; 450*36406Ssklower } 451*36406Ssklower } 452*36406Ssklower break; 453*36406Ssklower 454*36406Ssklower case TPOPT_FLAGS: 455*36406Ssklower IFDEBUG(D_REQUEST) 456*36406Ssklower printf("%s TPOPT_FLAGS value 0x%x *value 0x%x, flags 0x%x \n", 457*36406Ssklower cmd==PRCO_GETOPT?"GET":"SET", 458*36406Ssklower value, 459*36406Ssklower *value, 460*36406Ssklower tpcb->tp_flags); 461*36406Ssklower ENDDEBUG 462*36406Ssklower 463*36406Ssklower if ( cmd == PRCO_GETOPT ) { 464*36406Ssklower *(int *)value = (int)tpcb->tp_flags; 465*36406Ssklower (*mp)->m_len = sizeof(u_int); 466*36406Ssklower } else /* cmd == PRCO_SETOPT */ { 467*36406Ssklower error = EINVAL; goto done; 468*36406Ssklower } 469*36406Ssklower break; 470*36406Ssklower 471*36406Ssklower case TPOPT_PARAMS: 472*36406Ssklower /* This handles: 473*36406Ssklower * timer values, 474*36406Ssklower * class, use of transport expedited data, 475*36406Ssklower * max tpdu size, checksum, xtd format and 476*36406Ssklower * disconnect indications, and may get rid of connect/disc data 477*36406Ssklower */ 478*36406Ssklower IFDEBUG(D_SETPARAMS) 479*36406Ssklower printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, 480*36406Ssklower cmd==PRCO_GETOPT?"GET":"SET"); 481*36406Ssklower ENDDEBUG 482*36406Ssklower IFDEBUG(D_REQUEST) 483*36406Ssklower printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, 484*36406Ssklower cmd==PRCO_GETOPT?"GET":"SET"); 485*36406Ssklower ENDDEBUG 486*36406Ssklower 487*36406Ssklower if ( cmd == PRCO_GETOPT ) { 488*36406Ssklower *(struct tp_conn_param *)value = tpcb->_tp_param; 489*36406Ssklower (*mp)->m_len = sizeof(tpcb->_tp_param); 490*36406Ssklower } else /* cmd == PRCO_SETOPT */ { 491*36406Ssklower if( (error = 492*36406Ssklower tp_consistency(tpcb, TP_STRICT | TP_FORCE, 493*36406Ssklower (struct tp_conn_param *)value))==0) { 494*36406Ssklower /* 495*36406Ssklower * tp_consistency doesn't copy the whole set of params 496*36406Ssklower */ 497*36406Ssklower tpcb->_tp_param = *(struct tp_conn_param *)value; 498*36406Ssklower (*mp)->m_len = sizeof(tpcb->_tp_param); 499*36406Ssklower } 500*36406Ssklower } 501*36406Ssklower break; 502*36406Ssklower 503*36406Ssklower case TPOPT_PSTATISTICS: 504*36406Ssklower #ifdef TP_PERF_MEAS 505*36406Ssklower if (cmd == PRCO_SETOPT) { 506*36406Ssklower error = EINVAL; goto done; 507*36406Ssklower } 508*36406Ssklower IFPERF(tpcb) 509*36406Ssklower /* tp_p_meas is a cluster : "copy" it */ 510*36406Ssklower mclrefcnt[mtocl( (tpcb->tp_p_meas) )]++; 511*36406Ssklower (*mp)->m_off = (u_long)((int)tpcb->tp_p_meas - (int)(*mp)); 512*36406Ssklower (*mp)->m_len = sizeof(struct tp_pmeas); 513*36406Ssklower ENDPERF 514*36406Ssklower else { 515*36406Ssklower error = EINVAL; goto done; 516*36406Ssklower } 517*36406Ssklower break; 518*36406Ssklower #else 519*36406Ssklower error = EOPNOTSUPP; 520*36406Ssklower goto done; 521*36406Ssklower #endif TP_PERF_MEAS 522*36406Ssklower 523*36406Ssklower case TPOPT_CDDATA_CLEAR: 524*36406Ssklower if (cmd == PRCO_GETOPT) { 525*36406Ssklower error = EINVAL; 526*36406Ssklower } else { 527*36406Ssklower if ( tpcb->tp_flags & (TPF_CONN_DATA_OUT | TPF_DISC_DATA_OUT) ) { 528*36406Ssklower sbdrop(&so->so_snd, so->so_snd.sb_cc); 529*36406Ssklower tpcb->tp_flags &= ~(TPF_CONN_DATA_OUT | TPF_DISC_DATA_OUT); 530*36406Ssklower } 531*36406Ssklower } 532*36406Ssklower break; 533*36406Ssklower 534*36406Ssklower case TPOPT_DISC_DATA: 535*36406Ssklower /* drop through */ 536*36406Ssklower /* sending is for debugging purposes only -- we don't pretend 537*36406Ssklower * to support * data on connect or disconnect fully. It's a 538*36406Ssklower * kludge at best. 539*36406Ssklower * This data-on-connect is only for the active side. It's sort of 540*36406Ssklower * meaningless on the passive side (because 541*36406Ssklower * you can't reject a connect request based on the data 542*36406Ssklower * arriving w/ the CR, this, and because you'd have to 543*36406Ssklower * do this setsockopt system call for each accept). 544*36406Ssklower * but you can use it if you want. 545*36406Ssklower */ 546*36406Ssklower case TPOPT_CONN_DATA: 547*36406Ssklower if( tpcb->tp_class == TP_CLASS_0 ) { 548*36406Ssklower error = EOPNOTSUPP; 549*36406Ssklower break; 550*36406Ssklower } 551*36406Ssklower IFDEBUG(D_REQUEST) 552*36406Ssklower printf("%s\n", optname==TPOPT_DISC_DATA?"DISC data":"CONN data"); 553*36406Ssklower printf("m_len 0x%x, vallen 0x%x so_snd.cc 0x%x\n", 554*36406Ssklower (*mp)->m_len, val_len, so->so_snd.sb_cc); 555*36406Ssklower dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput: sosnd "); 556*36406Ssklower dump_mbuf(tpcb->tp_Xrcv.sb_mb, "tp_ctlout: tpXrcv "); 557*36406Ssklower ENDDEBUG 558*36406Ssklower if (cmd == PRCO_SETOPT) { 559*36406Ssklower /* can append connect data in several calls */ 560*36406Ssklower if (so->so_snd.sb_cc + val_len > 561*36406Ssklower (optname==TPOPT_CONN_DATA?TP_MAX_CR_DATA:TP_MAX_DR_DATA) ) { 562*36406Ssklower error = EMSGSIZE; goto done; 563*36406Ssklower } 564*36406Ssklower tpcb->tp_flags |= 565*36406Ssklower ((optname==TPOPT_CONN_DATA)?TPF_CONN_DATA_OUT:TPF_DISC_DATA_OUT); 566*36406Ssklower (*mp)->m_next = MNULL; 567*36406Ssklower (*mp)->m_act = 0; 568*36406Ssklower sbappendrecord( &so->so_snd, *mp); 569*36406Ssklower IFDEBUG(D_REQUEST) 570*36406Ssklower dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput after sbappendrecord"); 571*36406Ssklower ENDDEBUG 572*36406Ssklower IFTRACE(D_REQUEST) 573*36406Ssklower tptrace(TPPTmisc,"C/D DATA: flags snd.sbcc val_len", 574*36406Ssklower tpcb->tp_flags, so->so_snd.sb_cc,val_len,0); 575*36406Ssklower ENDTRACE 576*36406Ssklower *mp = MNULL; /* prevent sosetopt from freeing it! */ 577*36406Ssklower } else /* cmd == PRCO_GETOPT */ { 578*36406Ssklower register int len = tpcb->tp_Xrcv.sb_cc; 579*36406Ssklower 580*36406Ssklower /* getsockopt() allocated an mbuf but it's a whole lot easier 581*36406Ssklower * to do an m_copy than to explicitly copy from the socket buf 582*36406Ssklower * into the buffer provided by getsockopt() 583*36406Ssklower */ 584*36406Ssklower IFDEBUG(D_REQUEST) 585*36406Ssklower dump_mbuf(tpcb->tp_Xrcv.sb_mb, 586*36406Ssklower "tp_ctlout: tpXrcv before sbdrop"); 587*36406Ssklower ENDDEBUG 588*36406Ssklower if(len) { 589*36406Ssklower (void) m_freem(*mp); 590*36406Ssklower *mp = m_copy( tpcb->tp_Xrcv.sb_mb, 0, len); 591*36406Ssklower if( *mp != MNULL ) { 592*36406Ssklower (*mp)->m_act = 0; 593*36406Ssklower sbdrop( &tpcb->tp_Xrcv, len); 594*36406Ssklower } else { 595*36406Ssklower error = ENOBUFS; 596*36406Ssklower } 597*36406Ssklower } else { 598*36406Ssklower (*mp)->m_len = 0; 599*36406Ssklower } 600*36406Ssklower IFDEBUG(D_REQUEST) 601*36406Ssklower dump_mbuf(tpcb->tp_Xrcv.sb_mb, 602*36406Ssklower "tp_ctlout: tpXrcv after sbdrop"); 603*36406Ssklower ENDDEBUG 604*36406Ssklower /* a potential problem here is that REAL expedited may have arrived 605*36406Ssklower * after the data-on-connect 606*36406Ssklower * however, this presently works because incoming XPD_TPDUs are 607*36406Ssklower * dropped if tp_Xrcv.sb_cc != 0 608*36406Ssklower */ 609*36406Ssklower 610*36406Ssklower if( tpcb->tp_Xrcv.sb_cc == 0) 611*36406Ssklower tpcb->tp_flags &= 612*36406Ssklower optname == TPOPT_CONN_DATA?~TPF_CONN_DATA_IN:~TPF_DISC_DATA_IN; 613*36406Ssklower } 614*36406Ssklower break; 615*36406Ssklower 616*36406Ssklower case TPOPT_PERF_MEAS: 617*36406Ssklower #ifdef TP_PERF_MEAS 618*36406Ssklower if (cmd == PRCO_GETOPT) { 619*36406Ssklower *value = (u_int)tpcb->tp_perf_on; 620*36406Ssklower (*mp)->m_len = sizeof(u_int); 621*36406Ssklower } else if (cmd == PRCO_SETOPT) { 622*36406Ssklower (*mp)->m_len = 0; 623*36406Ssklower if ((*value) != 0 && (*value) != 1 ) 624*36406Ssklower error = EINVAL; 625*36406Ssklower else tpcb->tp_perf_on = (*value); 626*36406Ssklower } 627*36406Ssklower if( tpcb->tp_perf_on ) 628*36406Ssklower error = tp_setup_perf(tpcb); 629*36406Ssklower #else TP_PERF_MEAS 630*36406Ssklower error = EOPNOTSUPP; 631*36406Ssklower #endif TP_PERF_MEAS 632*36406Ssklower break; 633*36406Ssklower 634*36406Ssklower default: 635*36406Ssklower error = EOPNOTSUPP; 636*36406Ssklower } 637*36406Ssklower 638*36406Ssklower done: 639*36406Ssklower IFDEBUG(D_REQUEST) 640*36406Ssklower dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput sosnd at end"); 641*36406Ssklower dump_mbuf(*mp, "tp_ctloutput *mp"); 642*36406Ssklower ENDDEBUG 643*36406Ssklower /* 644*36406Ssklower * sigh: getsockopt looks only at m_len : all output data must 645*36406Ssklower * reside in the first mbuf 646*36406Ssklower */ 647*36406Ssklower if ( error && (*mp) != MNULL ) 648*36406Ssklower (*mp)->m_len = 0; 649*36406Ssklower if( (*mp) != MNULL ) { 650*36406Ssklower ASSERT ( m_compress(*mp, mp) <= MLEN ); 651*36406Ssklower IFDEBUG(D_REQUEST) 652*36406Ssklower dump_mbuf(*mp, "tp_ctloutput *mp after compress"); 653*36406Ssklower ENDDEBUG 654*36406Ssklower } 655*36406Ssklower 656*36406Ssklower splx(s); 657*36406Ssklower return error; 658*36406Ssklower } 659