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