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