|
|
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.