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