Commit | Line | Data |
---|---|---|
15637ed4 RG |
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 | * | |
b120d1cf | 33 | * From: @(#)tp_output.c 7.10 (Berkeley) 6/27/91 |
fde1aeb2 | 34 | * $Id: tp_output.c,v 1.3 1993/10/16 21:05:51 rgrimes Exp $ |
15637ed4 RG |
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 | */ | |
43371f85 | 63 | |
15637ed4 RG |
64 | /* |
65 | * ARGO TP | |
66 | * | |
15637ed4 RG |
67 | * In here is tp_ctloutput(), the guy called by [sg]etsockopt(), |
68 | */ | |
69 | ||
70 | #include "param.h" | |
71 | #include "mbuf.h" | |
72 | #include "systm.h" | |
73 | #include "socket.h" | |
74 | #include "socketvar.h" | |
75 | #include "protosw.h" | |
76 | #include "errno.h" | |
77 | #include "time.h" | |
78 | #include "tp_param.h" | |
79 | #include "tp_user.h" | |
80 | #include "tp_stat.h" | |
81 | #include "tp_ip.h" | |
82 | #include "tp_clnp.h" | |
83 | #include "tp_timer.h" | |
84 | #include "argo_debug.h" | |
85 | #include "tp_pcb.h" | |
86 | #include "tp_trace.h" | |
87 | #include "kernel.h" | |
88 | ||
89 | #define USERFLAGSMASK_G 0x0f00643b | |
90 | #define USERFLAGSMASK_S 0x0f000432 | |
91 | #define TPDUSIZESHIFT 24 | |
92 | #define CLASSHIFT 16 | |
93 | ||
94 | /* | |
95 | * NAME: tp_consistency() | |
96 | * | |
97 | * CALLED FROM: | |
98 | * tp_ctloutput(), tp_input() | |
99 | * | |
100 | * FUNCTION and ARGUMENTS: | |
101 | * Checks the consistency of options and tpdusize with class, | |
102 | * using the parameters passed in via (param). | |
103 | * (cmd) may be TP_STRICT or TP_FORCE or both. | |
104 | * Force means it will set all the values in (tpcb) to those in | |
105 | * the input arguements iff no errors were encountered. | |
106 | * Strict means that no inconsistency will be tolerated. If it's | |
107 | * not used, checksum and tpdusize inconsistencies will be tolerated. | |
108 | * The reason for this is that in some cases, when we're negotiating down | |
109 | * from class 4, these options should be changed but should not | |
110 | * cause negotiation to fail. | |
111 | * | |
112 | * RETURNS | |
113 | * E* or EOK | |
114 | * E* if the various parms aren't ok for a given class | |
115 | * EOK if they are ok for a given class | |
116 | */ | |
117 | ||
118 | int | |
119 | tp_consistency( tpcb, cmd, param ) | |
fde1aeb2 | 120 | struct tp_pcb *tpcb; |
15637ed4 RG |
121 | u_int cmd; |
122 | struct tp_conn_param *param; | |
15637ed4 RG |
123 | { |
124 | register int error = EOK; | |
125 | int class_to_use = tp_mask_to_num(param->p_class); | |
126 | ||
127 | IFTRACE(D_SETPARAMS) | |
128 | tptrace(TPPTmisc, | |
129 | "tp_consist enter class_to_use dontchange param.class cmd", | |
130 | class_to_use, param->p_dont_change_params, param->p_class, cmd); | |
131 | ENDTRACE | |
132 | IFDEBUG(D_SETPARAMS) | |
133 | printf("tp_consistency %s %s\n", | |
134 | cmd& TP_FORCE? "TP_FORCE": "", | |
135 | cmd& TP_STRICT? "TP_STRICT":""); | |
136 | ENDDEBUG | |
137 | if ((cmd & TP_FORCE) && (param->p_dont_change_params)) { | |
138 | cmd &= ~TP_FORCE; | |
139 | } | |
140 | /* can switch net services within a domain, but | |
141 | * cannot switch domains | |
142 | */ | |
143 | switch( param->p_netservice) { | |
144 | case ISO_CONS: | |
145 | case ISO_CLNS: | |
146 | case ISO_COSNS: | |
147 | /* param->p_netservice in ISO DOMAIN */ | |
148 | if(tpcb->tp_domain != AF_ISO ) { | |
149 | error = EINVAL; goto done; | |
150 | } | |
151 | break; | |
152 | case IN_CLNS: | |
153 | /* param->p_netservice in INET DOMAIN */ | |
154 | if( tpcb->tp_domain != AF_INET ) { | |
155 | error = EINVAL; goto done; | |
156 | } | |
157 | break; | |
158 | /* no others not possible-> netservice is a 2-bit field! */ | |
159 | } | |
160 | ||
161 | IFDEBUG(D_SETPARAMS) | |
162 | printf("p_class 0x%x, class_to_use 0x%x\n", param->p_class, | |
163 | class_to_use); | |
164 | ENDDEBUG | |
b120d1cf RG |
165 | #ifdef XXXRWGXXX |
166 | /* this next line is questionable p_netservice is u_char, how can it | |
167 | * ever be less than 0 ?? | |
168 | */ | |
15637ed4 | 169 | if((param->p_netservice < 0) || (param->p_netservice > TP_MAX_NETSERVICES)){ |
b120d1cf RG |
170 | #endif |
171 | if(/*(param->p_netservice < 0) ||*/ (param->p_netservice > TP_MAX_NETSERVICES)){ | |
15637ed4 RG |
172 | error = EINVAL; goto done; |
173 | } | |
174 | if( (param->p_class & TP_CLASSES_IMPLEMENTED) == 0 ) { | |
175 | error = EINVAL; goto done; | |
176 | } | |
177 | IFDEBUG(D_SETPARAMS) | |
178 | printf("Nretrans 0x%x\n", param->p_Nretrans ); | |
179 | ENDDEBUG | |
180 | if( ( param->p_Nretrans < 1 ) || | |
181 | (param->p_cr_ticks < 1) || (param->p_cc_ticks < 1) ) { | |
182 | /* bad for any class because negot has to be done a la class 4 */ | |
183 | error = EINVAL; goto done; | |
184 | } | |
185 | IFDEBUG(D_SETPARAMS) | |
186 | printf("winsize 0x%x\n", param->p_winsize ); | |
187 | ENDDEBUG | |
188 | if( (param->p_winsize < 128 ) || | |
189 | (param->p_winsize < param->p_tpdusize ) || | |
190 | (param->p_winsize > ((1+SB_MAX)>>2 /* 1/4 of the max */)) ) { | |
191 | error = EINVAL; goto done; | |
192 | } else { | |
193 | if( tpcb->tp_state == TP_CLOSED ) | |
194 | soreserve(tpcb->tp_sock, (u_long)param->p_winsize, | |
195 | (u_long)param->p_winsize); | |
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 | /* Enforce Negotation rules below */ | |
310 | if (tpcb->tp_tpdusize > param->p_tpdusize) | |
311 | tpcb->tp_tpdusize = param->p_tpdusize; | |
312 | tpcb->tp_class = param->p_class; | |
313 | if (tpcb->tp_use_checksum || param->p_use_checksum) | |
314 | tpcb->tp_use_checksum = 1; | |
315 | if (!tpcb->tp_xpd_service || !param->p_xpd_service) | |
316 | tpcb->tp_xpd_service = 0; | |
317 | if (!tpcb->tp_xtd_format || !param->p_xtd_format) | |
318 | tpcb->tp_xtd_format = 0; | |
319 | } | |
320 | ||
321 | done: | |
322 | ||
323 | IFTRACE(D_CONN) | |
324 | tptrace(TPPTmisc, "tp_consist returns class xtdfmt cmd", | |
325 | error, tpcb->tp_class, tpcb->tp_xtd_format, cmd); | |
326 | ENDTRACE | |
327 | IFDEBUG(D_CONN) | |
328 | printf( | |
329 | "tp_consist rtns 0x%x class 0x%x xtd_fmt 0x%x cmd 0x%x\n", | |
330 | error, tpcb->tp_class, tpcb->tp_xtd_format, cmd); | |
331 | ENDDEBUG | |
332 | return error; | |
333 | } | |
334 | ||
335 | /* | |
336 | * NAME: tp_ctloutput() | |
337 | * | |
338 | * CALLED FROM: | |
339 | * [sg]etsockopt(), via so[sg]etopt(). | |
340 | * | |
341 | * FUNCTION and ARGUMENTS: | |
342 | * Implements the socket options at transport level. | |
343 | * (cmd) is either PRCO_SETOPT or PRCO_GETOPT (see ../sys/protosw.h). | |
344 | * (so) is the socket. | |
345 | * (level) is SOL_TRANSPORT (see ../sys/socket.h) | |
346 | * (optname) is the particular command or option to be set. | |
347 | * (**mp) is an mbuf structure. | |
348 | * | |
349 | * RETURN VALUE: | |
350 | * ENOTSOCK if the socket hasn't got an associated tpcb | |
351 | * EINVAL if | |
352 | * trying to set window too big | |
353 | * trying to set illegal max tpdu size | |
354 | * trying to set illegal credit fraction | |
355 | * trying to use unknown or unimplemented class of TP | |
356 | * structure passed to set timer values is wrong size | |
357 | * illegal combination of command/GET-SET option, | |
358 | * e.g., GET w/ TPOPT_CDDATA_CLEAR: | |
359 | * EOPNOTSUPP if the level isn't transport, or command is neither GET nor SET | |
360 | * or if the transport-specific command is not implemented | |
361 | * EISCONN if trying a command that isn't allowed after a connection | |
362 | * is established | |
363 | * ENOTCONN if trying a command that is allowed only if a connection is | |
364 | * established | |
365 | * EMSGSIZE if trying to give too much data on connect/disconnect | |
366 | * | |
367 | * SIDE EFFECTS: | |
368 | * | |
369 | * NOTES: | |
370 | */ | |
371 | ProtoHook | |
372 | tp_ctloutput(cmd, so, level, optname, mp) | |
373 | int cmd, level, optname; | |
374 | struct socket *so; | |
375 | struct mbuf **mp; | |
376 | { | |
377 | struct tp_pcb *tpcb = sototpcb(so); | |
378 | int s = splnet(); | |
379 | caddr_t value; | |
380 | unsigned val_len; | |
381 | int error = 0; | |
382 | ||
383 | IFTRACE(D_REQUEST) | |
384 | tptrace(TPPTmisc, "tp_ctloutput cmd so optname mp", | |
385 | cmd, so, optname, mp); | |
386 | ENDTRACE | |
387 | IFDEBUG(D_REQUEST) | |
388 | printf( | |
389 | "tp_ctloutput so 0x%x cmd 0x%x optname 0x%x, mp 0x%x *mp 0x%x tpcb 0x%x\n", | |
390 | so, cmd, optname, mp, mp?*mp:0, tpcb); | |
391 | ENDDEBUG | |
392 | if( tpcb == (struct tp_pcb *)0 ) { | |
393 | error = ENOTSOCK; goto done; | |
394 | } | |
395 | if(*mp == MNULL) { | |
396 | register struct mbuf *m; | |
397 | ||
398 | MGET(m, M_DONTWAIT, TPMT_SONAME); /* does off, type, next */ | |
399 | if (m == NULL) { | |
400 | splx(s); | |
401 | return ENOBUFS; | |
402 | } | |
403 | m->m_len = 0; | |
404 | m->m_act = 0; | |
405 | *mp = m; | |
406 | } | |
407 | ||
408 | /* | |
409 | * Hook so one can set network options via a tp socket. | |
410 | */ | |
411 | if ( level == SOL_NETWORK ) { | |
412 | if ((tpcb->tp_nlproto == NULL) || (tpcb->tp_npcb == NULL)) | |
413 | error = ENOTSOCK; | |
414 | else if (tpcb->tp_nlproto->nlp_ctloutput == NULL) | |
415 | error = EOPNOTSUPP; | |
416 | else | |
417 | error = (tpcb->tp_nlproto->nlp_ctloutput)(cmd, optname, | |
418 | tpcb->tp_npcb, *mp); | |
419 | goto done; | |
420 | } else if ( level != SOL_TRANSPORT ) { | |
421 | error = EOPNOTSUPP; goto done; | |
422 | } | |
423 | if (cmd != PRCO_GETOPT && cmd != PRCO_SETOPT) { | |
424 | error = EOPNOTSUPP; goto done; | |
425 | } | |
426 | if ( so->so_error ) { | |
427 | error = so->so_error; goto done; | |
428 | } | |
429 | ||
430 | /* The only options allowed after connection is established | |
431 | * are GET (anything) and SET DISC DATA and SET PERF MEAS | |
432 | */ | |
433 | if ( ((so->so_state & SS_ISCONNECTING)||(so->so_state & SS_ISCONNECTED)) | |
434 | && | |
435 | (cmd == PRCO_SETOPT && | |
436 | optname != TPOPT_DISC_DATA && | |
437 | optname != TPOPT_CFRM_DATA && | |
438 | optname != TPOPT_PERF_MEAS && | |
439 | optname != TPOPT_CDDATA_CLEAR ) ) { | |
440 | error = EISCONN; goto done; | |
441 | } | |
442 | /* The only options allowed after disconnection are GET DISC DATA, | |
443 | * and TPOPT_PSTATISTICS | |
444 | * and they're not allowed if the ref timer has gone off, because | |
445 | * the tpcb is gone | |
446 | */ | |
447 | if ((so->so_state & (SS_ISCONNECTED | SS_ISCONFIRMING)) == 0) { | |
448 | if ( so->so_tpcb == (caddr_t)0 ) { | |
449 | error = ENOTCONN; goto done; | |
450 | } | |
451 | if ( (tpcb->tp_state == TP_REFWAIT || tpcb->tp_state == TP_CLOSING) && | |
452 | (optname != TPOPT_DISC_DATA && optname != TPOPT_PSTATISTICS)) { | |
453 | error = ENOTCONN; goto done; | |
454 | } | |
455 | } | |
456 | ||
457 | value = mtod(*mp, caddr_t); /* it's aligned, don't worry, | |
458 | * but lint complains about it | |
459 | */ | |
460 | val_len = (*mp)->m_len; | |
461 | ||
462 | switch (optname) { | |
463 | ||
464 | case TPOPT_INTERCEPT: | |
465 | if ((so->so_state & SS_PRIV) == 0) { | |
466 | error = EPERM; | |
467 | break; | |
468 | } else if (cmd != PRCO_SETOPT || tpcb->tp_state != TP_LISTENING) | |
469 | error = EINVAL; | |
470 | else { | |
471 | register struct tp_pcb *t = 0; | |
472 | struct mbuf *m = m_getclr(M_WAIT, MT_SONAME); | |
473 | struct sockaddr *sa = mtod(m, struct sockaddr *); | |
474 | (*tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, m, TP_LOCAL); | |
475 | switch (sa->sa_family) { | |
476 | case AF_ISO: | |
477 | if (((struct sockaddr_iso *)sa)->siso_nlen == 0) | |
478 | default: error = EINVAL; | |
479 | break; | |
480 | case AF_INET: | |
481 | if (((struct sockaddr_in *)sa)->sin_addr.s_addr == 0) | |
482 | error = EINVAL; | |
483 | break; | |
484 | } | |
485 | for (t = tp_intercepts; t; t = t->tp_nextlisten) { | |
486 | if (t->tp_nlproto->nlp_afamily != tpcb->tp_nlproto->nlp_afamily) | |
487 | continue; | |
488 | if ((*t->tp_nlproto->nlp_cmpnetaddr)(t->tp_npcb, sa, TP_LOCAL)) | |
489 | error = EADDRINUSE; | |
490 | } | |
491 | m_freem(m); | |
492 | if (error) | |
493 | break; | |
494 | } | |
495 | { | |
496 | register struct tp_pcb **tt; | |
497 | for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten)) | |
498 | if (*tt == tpcb) | |
499 | break; | |
500 | if (*tt) | |
501 | *tt = tpcb->tp_nextlisten; | |
502 | else | |
503 | {error = EHOSTUNREACH; goto done; } | |
504 | } | |
505 | tpcb->tp_nextlisten = tp_intercepts; | |
506 | tp_intercepts = tpcb; | |
507 | break; | |
508 | ||
509 | case TPOPT_MY_TSEL: | |
510 | if ( cmd == PRCO_GETOPT ) { | |
511 | ASSERT( tpcb->tp_lsuffixlen <= MAX_TSAP_SEL_LEN ); | |
512 | bcopy((caddr_t)tpcb->tp_lsuffix, value, tpcb->tp_lsuffixlen); | |
513 | (*mp)->m_len = tpcb->tp_lsuffixlen; | |
514 | } else /* cmd == PRCO_SETOPT */ { | |
515 | if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { | |
516 | printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); | |
517 | error = EINVAL; | |
518 | } else { | |
519 | bcopy(value, (caddr_t)tpcb->tp_lsuffix, val_len); | |
520 | tpcb->tp_lsuffixlen = val_len; | |
521 | } | |
522 | } | |
523 | break; | |
524 | ||
525 | case TPOPT_PEER_TSEL: | |
526 | if ( cmd == PRCO_GETOPT ) { | |
527 | ASSERT( tpcb->tp_fsuffixlen <= MAX_TSAP_SEL_LEN ); | |
528 | bcopy((caddr_t)tpcb->tp_fsuffix, value, tpcb->tp_fsuffixlen); | |
529 | (*mp)->m_len = tpcb->tp_fsuffixlen; | |
530 | } else /* cmd == PRCO_SETOPT */ { | |
531 | if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { | |
532 | printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); | |
533 | error = EINVAL; | |
534 | } else { | |
535 | bcopy(value, (caddr_t)tpcb->tp_fsuffix, val_len); | |
536 | tpcb->tp_fsuffixlen = val_len; | |
537 | } | |
538 | } | |
539 | break; | |
540 | ||
541 | case TPOPT_FLAGS: | |
542 | IFDEBUG(D_REQUEST) | |
543 | printf("%s TPOPT_FLAGS value 0x%x *value 0x%x, flags 0x%x \n", | |
544 | cmd==PRCO_GETOPT?"GET":"SET", | |
545 | value, | |
546 | *value, | |
547 | tpcb->tp_flags); | |
548 | ENDDEBUG | |
549 | ||
550 | if ( cmd == PRCO_GETOPT ) { | |
551 | *(int *)value = (int)tpcb->tp_flags; | |
552 | (*mp)->m_len = sizeof(u_int); | |
553 | } else /* cmd == PRCO_SETOPT */ { | |
554 | error = EINVAL; goto done; | |
555 | } | |
556 | break; | |
557 | ||
558 | case TPOPT_PARAMS: | |
559 | /* This handles: | |
560 | * timer values, | |
561 | * class, use of transport expedited data, | |
562 | * max tpdu size, checksum, xtd format and | |
563 | * disconnect indications, and may get rid of connect/disc data | |
564 | */ | |
565 | IFDEBUG(D_SETPARAMS) | |
566 | printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, | |
567 | cmd==PRCO_GETOPT?"GET":"SET"); | |
568 | ENDDEBUG | |
569 | IFDEBUG(D_REQUEST) | |
570 | printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, | |
571 | cmd==PRCO_GETOPT?"GET":"SET"); | |
572 | ENDDEBUG | |
573 | ||
574 | if ( cmd == PRCO_GETOPT ) { | |
575 | *(struct tp_conn_param *)value = tpcb->_tp_param; | |
576 | (*mp)->m_len = sizeof(tpcb->_tp_param); | |
577 | } else /* cmd == PRCO_SETOPT */ { | |
578 | if( (error = | |
579 | tp_consistency(tpcb, TP_STRICT | TP_FORCE, | |
580 | (struct tp_conn_param *)value))==0) { | |
581 | /* | |
582 | * tp_consistency doesn't copy the whole set of params | |
583 | */ | |
584 | tpcb->_tp_param = *(struct tp_conn_param *)value; | |
585 | (*mp)->m_len = sizeof(tpcb->_tp_param); | |
586 | } | |
587 | } | |
588 | break; | |
589 | ||
590 | case TPOPT_PSTATISTICS: | |
591 | #ifdef TP_PERF_MEAS | |
592 | if (cmd == PRCO_SETOPT) { | |
593 | error = EINVAL; goto done; | |
594 | } | |
595 | IFPERF(tpcb) | |
596 | if (*mp) { | |
597 | struct mbuf * n; | |
598 | do { | |
599 | MFREE(*mp, n); | |
600 | *mp = n; | |
601 | } while (n); | |
602 | } | |
603 | *mp = m_copym(tpcb->tp_p_mbuf, (int)M_COPYALL, M_WAITOK); | |
604 | ENDPERF | |
605 | else { | |
606 | error = EINVAL; goto done; | |
607 | } | |
608 | break; | |
609 | #else | |
610 | error = EOPNOTSUPP; | |
611 | goto done; | |
612 | #endif TP_PERF_MEAS | |
613 | ||
614 | case TPOPT_CDDATA_CLEAR: | |
615 | if (cmd == PRCO_GETOPT) { | |
616 | error = EINVAL; | |
617 | } else { | |
618 | if (tpcb->tp_ucddata) { | |
619 | m_freem(tpcb->tp_ucddata); | |
620 | tpcb->tp_ucddata = 0; | |
621 | } | |
622 | } | |
623 | break; | |
624 | ||
625 | case TPOPT_CFRM_DATA: | |
626 | case TPOPT_DISC_DATA: | |
627 | case TPOPT_CONN_DATA: | |
628 | if( tpcb->tp_class == TP_CLASS_0 ) { | |
629 | error = EOPNOTSUPP; | |
630 | break; | |
631 | } | |
632 | IFDEBUG(D_REQUEST) | |
633 | printf("%s\n", optname==TPOPT_DISC_DATA?"DISC data":"CONN data"); | |
634 | printf("m_len 0x%x, vallen 0x%x so_snd.cc 0x%x\n", | |
635 | (*mp)->m_len, val_len, so->so_snd.sb_cc); | |
636 | dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput: sosnd "); | |
637 | ENDDEBUG | |
638 | if (cmd == PRCO_SETOPT) { | |
639 | int len = tpcb->tp_ucddata ? tpcb->tp_ucddata->m_len : 0; | |
640 | /* can append connect data in several calls */ | |
641 | if (len + val_len > | |
642 | (optname==TPOPT_CONN_DATA?TP_MAX_CR_DATA:TP_MAX_DR_DATA) ) { | |
643 | error = EMSGSIZE; goto done; | |
644 | } | |
645 | (*mp)->m_next = MNULL; | |
646 | (*mp)->m_act = 0; | |
647 | if (tpcb->tp_ucddata) | |
648 | m_cat(tpcb->tp_ucddata, *mp); | |
649 | else | |
650 | tpcb->tp_ucddata = *mp; | |
651 | IFDEBUG(D_REQUEST) | |
652 | dump_mbuf(tpcb->tp_ucddata, "tp_ctloutput after CONN_DATA"); | |
653 | ENDDEBUG | |
654 | IFTRACE(D_REQUEST) | |
655 | tptrace(TPPTmisc,"C/D DATA: flags snd.sbcc val_len", | |
656 | tpcb->tp_flags, so->so_snd.sb_cc,val_len,0); | |
657 | ENDTRACE | |
658 | *mp = MNULL; /* prevent sosetopt from freeing it! */ | |
659 | if (optname == TPOPT_CFRM_DATA && (so->so_state & SS_ISCONFIRMING)) | |
660 | (void) tp_confirm(tpcb); | |
661 | } | |
662 | break; | |
663 | ||
664 | case TPOPT_PERF_MEAS: | |
665 | #ifdef TP_PERF_MEAS | |
666 | if (cmd == PRCO_GETOPT) { | |
667 | *value = (u_int)tpcb->tp_perf_on; | |
668 | (*mp)->m_len = sizeof(u_int); | |
669 | } else if (cmd == PRCO_SETOPT) { | |
670 | (*mp)->m_len = 0; | |
671 | if ((*value) != 0 && (*value) != 1 ) | |
672 | error = EINVAL; | |
673 | else tpcb->tp_perf_on = (*value); | |
674 | } | |
675 | if( tpcb->tp_perf_on ) | |
676 | error = tp_setup_perf(tpcb); | |
677 | #else TP_PERF_MEAS | |
678 | error = EOPNOTSUPP; | |
679 | #endif TP_PERF_MEAS | |
680 | break; | |
681 | ||
682 | default: | |
683 | error = EOPNOTSUPP; | |
684 | } | |
685 | ||
686 | done: | |
687 | IFDEBUG(D_REQUEST) | |
688 | dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput sosnd at end"); | |
689 | dump_mbuf(*mp, "tp_ctloutput *mp"); | |
690 | ENDDEBUG | |
691 | /* | |
692 | * sigh: getsockopt looks only at m_len : all output data must | |
693 | * reside in the first mbuf | |
694 | */ | |
695 | if ( error && (*mp) != MNULL ) | |
696 | (*mp)->m_len = 0; | |
697 | if( (*mp) != MNULL ) { | |
698 | ASSERT ( m_compress(*mp, mp) <= MLEN ); | |
699 | IFDEBUG(D_REQUEST) | |
700 | dump_mbuf(*mp, "tp_ctloutput *mp after compress"); | |
701 | ENDDEBUG | |
702 | } | |
703 | ||
704 | splx(s); | |
705 | return error; | |
706 | } |