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