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