]> git.saurik.com Git - apple/xnu.git/blob - bsd/netiso/tp_output.c
xnu-201.42.3.tar.gz
[apple/xnu.git] / bsd / netiso / tp_output.c
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 }