]>
Commit | Line | Data |
---|---|---|
1c79356b A |
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_pcb.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 | * | |
87 | * This is the initialization and cleanup stuff - | |
88 | * for the tp machine in general as well as for the individual pcbs. | |
89 | * tp_init() is called at system startup. tp_attach() and tp_getref() are | |
90 | * called when a socket is created. tp_detach() and tp_freeref() | |
91 | * are called during the closing stage and/or when the reference timer | |
92 | * goes off. | |
93 | * tp_soisdisconnecting() and tp_soisdisconnected() are tp-specific | |
94 | * versions of soisconnect* | |
95 | * and are called (obviously) during the closing phase. | |
96 | * | |
97 | */ | |
98 | ||
99 | #include <sys/param.h> | |
100 | #include <sys/systm.h> | |
101 | #include <sys/mbuf.h> | |
102 | #include <sys/socket.h> | |
103 | #include <sys/socketvar.h> | |
104 | #include <sys/domain.h> | |
105 | #include <sys/protosw.h> | |
106 | #include <sys/errno.h> | |
107 | #include <sys/time.h> | |
108 | ||
109 | #include <netiso/argo_debug.h> | |
110 | #include <netiso/tp_param.h> | |
111 | #include <netiso/tp_timer.h> | |
112 | #include <netiso/tp_ip.h> | |
113 | #include <netiso/tp_stat.h> | |
114 | #include <netiso/tp_pcb.h> | |
115 | #include <netiso/tp_tpdu.h> | |
116 | #include <netiso/tp_trace.h> | |
117 | #include <netiso/tp_meas.h> | |
118 | #include <netiso/tp_seq.h> | |
119 | #include <netiso/tp_clnp.h> | |
120 | ||
121 | /* ticks are in units of: | |
122 | * 500 nano-fortnights ;-) or | |
123 | * 500 ms or | |
124 | * 1/2 second | |
125 | */ | |
126 | ||
127 | struct tp_conn_param tp_conn_param[] = { | |
128 | /* ISO_CLNS: TP4 CONNECTION LESS */ | |
129 | { | |
130 | TP_NRETRANS, /* short p_Nretrans; */ | |
131 | 20, /* 10 sec */ /* short p_dr_ticks; */ | |
132 | ||
133 | 20, /* 10 sec */ /* short p_cc_ticks; */ | |
134 | 20, /* 10 sec */ /* short p_dt_ticks; */ | |
135 | ||
136 | 40, /* 20 sec */ /* short p_x_ticks; */ | |
137 | 80, /* 40 sec */ /* short p_cr_ticks;*/ | |
138 | ||
139 | 240, /* 2 min */ /* short p_keepalive_ticks;*/ | |
140 | 10, /* 5 sec */ /* short p_sendack_ticks; */ | |
141 | ||
142 | 600, /* 5 min */ /* short p_ref_ticks; */ | |
143 | 360, /* 3 min */ /* short p_inact_ticks; */ | |
144 | ||
145 | (short) 100, /* short p_lcdtfract */ | |
146 | (short) TP_SOCKBUFSIZE, /* short p_winsize */ | |
147 | TP_TPDUSIZE, /* u_char p_tpdusize */ | |
148 | ||
149 | TPACK_WINDOW, /* 4 bits p_ack_strat */ | |
150 | TPRX_USE_CW | TPRX_FASTSTART, | |
151 | /* 4 bits p_rx_strat*/ | |
152 | TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */ | |
153 | 1, /* 1 bit xtd format */ | |
154 | 1, /* 1 bit xpd service */ | |
155 | 1, /* 1 bit use_checksum */ | |
156 | 0, /* 1 bit use net xpd */ | |
157 | 0, /* 1 bit use rcc */ | |
158 | 0, /* 1 bit use efc */ | |
159 | 1, /* no disc indications */ | |
160 | 0, /* don't change params */ | |
161 | ISO_CLNS, /* p_netservice */ | |
162 | }, | |
163 | /* IN_CLNS: TP4 CONNECTION LESS */ | |
164 | { | |
165 | TP_NRETRANS, /* short p_Nretrans; */ | |
166 | 20, /* 10 sec */ /* short p_dr_ticks; */ | |
167 | ||
168 | 20, /* 10 sec */ /* short p_cc_ticks; */ | |
169 | 20, /* 10 sec */ /* short p_dt_ticks; */ | |
170 | ||
171 | 40, /* 20 sec */ /* short p_x_ticks; */ | |
172 | 80, /* 40 sec */ /* short p_cr_ticks;*/ | |
173 | ||
174 | 240, /* 2 min */ /* short p_keepalive_ticks;*/ | |
175 | 10, /* 5 sec */ /* short p_sendack_ticks; */ | |
176 | ||
177 | 600, /* 5 min */ /* short p_ref_ticks; */ | |
178 | 360, /* 3 min */ /* short p_inact_ticks; */ | |
179 | ||
180 | (short) 100, /* short p_lcdtfract */ | |
181 | (short) TP_SOCKBUFSIZE, /* short p_winsize */ | |
182 | TP_TPDUSIZE, /* u_char p_tpdusize */ | |
183 | ||
184 | TPACK_WINDOW, /* 4 bits p_ack_strat */ | |
185 | TPRX_USE_CW | TPRX_FASTSTART, | |
186 | /* 4 bits p_rx_strat*/ | |
187 | TP_CLASS_4, /* 5 bits p_class */ | |
188 | 1, /* 1 bit xtd format */ | |
189 | 1, /* 1 bit xpd service */ | |
190 | 1, /* 1 bit use_checksum */ | |
191 | 0, /* 1 bit use net xpd */ | |
192 | 0, /* 1 bit use rcc */ | |
193 | 0, /* 1 bit use efc */ | |
194 | 1, /* no disc indications */ | |
195 | 0, /* don't change params */ | |
196 | IN_CLNS, /* p_netservice */ | |
197 | }, | |
198 | /* ISO_CONS: TP0 CONNECTION MODE */ | |
199 | { | |
200 | TP_NRETRANS, /* short p_Nretrans; */ | |
201 | 0, /* n/a */ /* short p_dr_ticks; */ | |
202 | ||
203 | 40, /* 20 sec */ /* short p_cc_ticks; */ | |
204 | 0, /* n/a */ /* short p_dt_ticks; */ | |
205 | ||
206 | 0, /* n/a */ /* short p_x_ticks; */ | |
207 | 360, /* 3 min */ /* short p_cr_ticks;*/ | |
208 | ||
209 | 0, /* n/a */ /* short p_keepalive_ticks;*/ | |
210 | 0, /* n/a */ /* short p_sendack_ticks; */ | |
211 | ||
212 | 600, /* for cr/cc to clear *//* short p_ref_ticks; */ | |
213 | 0, /* n/a */ /* short p_inact_ticks; */ | |
214 | ||
215 | /* Use tp4 defaults just in case the user changes ONLY | |
216 | * the class | |
217 | */ | |
218 | (short) 100, /* short p_lcdtfract */ | |
219 | (short) TP0_SOCKBUFSIZE, /* short p_winsize */ | |
220 | TP0_TPDUSIZE, /* 8 bits p_tpdusize */ | |
221 | ||
222 | 0, /* 4 bits p_ack_strat */ | |
223 | 0, /* 4 bits p_rx_strat*/ | |
224 | TP_CLASS_0, /* 5 bits p_class */ | |
225 | 0, /* 1 bit xtd format */ | |
226 | 0, /* 1 bit xpd service */ | |
227 | 0, /* 1 bit use_checksum */ | |
228 | 0, /* 1 bit use net xpd */ | |
229 | 0, /* 1 bit use rcc */ | |
230 | 0, /* 1 bit use efc */ | |
231 | 0, /* no disc indications */ | |
232 | 0, /* don't change params */ | |
233 | ISO_CONS, /* p_netservice */ | |
234 | }, | |
235 | /* ISO_COSNS: TP4 CONNECTION LESS SERVICE over CONSNS */ | |
236 | { | |
237 | TP_NRETRANS, /* short p_Nretrans; */ | |
238 | 40, /* 20 sec */ /* short p_dr_ticks; */ | |
239 | ||
240 | 40, /* 20 sec */ /* short p_cc_ticks; */ | |
241 | 80, /* 40 sec */ /* short p_dt_ticks; */ | |
242 | ||
243 | 120, /* 1 min */ /* short p_x_ticks; */ | |
244 | 360, /* 3 min */ /* short p_cr_ticks;*/ | |
245 | ||
246 | 360, /* 3 min */ /* short p_keepalive_ticks;*/ | |
247 | 20, /* 10 sec */ /* short p_sendack_ticks; */ | |
248 | ||
249 | 600, /* 5 min */ /* short p_ref_ticks; */ | |
250 | 480, /* 4 min */ /* short p_inact_ticks; */ | |
251 | ||
252 | (short) 100, /* short p_lcdtfract */ | |
253 | (short) TP0_SOCKBUFSIZE, /* short p_winsize */ | |
254 | TP0_TPDUSIZE, /* u_char p_tpdusize */ | |
255 | ||
256 | TPACK_WINDOW, /* 4 bits p_ack_strat */ | |
257 | TPRX_USE_CW , /* No fast start */ | |
258 | /* 4 bits p_rx_strat*/ | |
259 | TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */ | |
260 | 0, /* 1 bit xtd format */ | |
261 | 1, /* 1 bit xpd service */ | |
262 | 1, /* 1 bit use_checksum */ | |
263 | 0, /* 1 bit use net xpd */ | |
264 | 0, /* 1 bit use rcc */ | |
265 | 0, /* 1 bit use efc */ | |
266 | 0, /* no disc indications */ | |
267 | 0, /* don't change params */ | |
268 | ISO_COSNS, /* p_netservice */ | |
269 | }, | |
270 | }; | |
271 | ||
272 | #if INET | |
273 | int in_putnetaddr(); | |
274 | int in_getnetaddr(); | |
275 | int in_cmpnetaddr(); | |
276 | int in_putsufx(); | |
277 | int in_getsufx(); | |
278 | int in_recycle_tsuffix(); | |
279 | int tpip_mtu(); | |
280 | int in_pcbbind(); | |
281 | int in_pcbconnect(); | |
282 | int in_pcbdisconnect(); | |
283 | int in_pcbdetach(); | |
284 | int in_pcballoc(); | |
285 | int tpip_output(); | |
286 | int tpip_output_dg(); | |
287 | struct inpcb tp_inpcb; | |
288 | #endif /* INET */ | |
289 | #if ISO | |
290 | int iso_putnetaddr(); | |
291 | int iso_getnetaddr(); | |
292 | int iso_cmpnetaddr(); | |
293 | int iso_putsufx(); | |
294 | int iso_getsufx(); | |
295 | int iso_recycle_tsuffix(); | |
296 | int tpclnp_mtu(); | |
297 | int iso_pcbbind(); | |
298 | int iso_pcbconnect(); | |
299 | int iso_pcbdisconnect(); | |
300 | int iso_pcbdetach(); | |
301 | int iso_pcballoc(); | |
302 | int tpclnp_output(); | |
303 | int tpclnp_output_dg(); | |
304 | int iso_nlctloutput(); | |
305 | struct isopcb tp_isopcb; | |
306 | #endif /* ISO */ | |
307 | #if TPCONS | |
308 | int iso_putnetaddr(); | |
309 | int iso_getnetaddr(); | |
310 | int iso_cmpnetaddr(); | |
311 | int iso_putsufx(); | |
312 | int iso_getsufx(); | |
313 | int iso_recycle_tsuffix(); | |
314 | int iso_pcbbind(); | |
315 | int tpcons_pcbconnect(); | |
316 | int tpclnp_mtu(); | |
317 | int iso_pcbdisconnect(); | |
318 | int iso_pcbdetach(); | |
319 | int iso_pcballoc(); | |
320 | int tpcons_output(); | |
321 | struct isopcb tp_isopcb; | |
322 | #endif /* TPCONS */ | |
323 | ||
324 | ||
325 | struct nl_protosw nl_protosw[] = { | |
326 | /* ISO_CLNS */ | |
327 | #if ISO | |
328 | { AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr, | |
329 | iso_putsufx, iso_getsufx, | |
330 | iso_recycle_tsuffix, | |
331 | tpclnp_mtu, iso_pcbbind, iso_pcbconnect, | |
332 | iso_pcbdisconnect, iso_pcbdetach, | |
333 | iso_pcballoc, | |
334 | tpclnp_output, tpclnp_output_dg, iso_nlctloutput, | |
335 | (caddr_t) &tp_isopcb, | |
336 | }, | |
337 | #else | |
338 | { 0 }, | |
339 | #endif /* ISO */ | |
340 | /* IN_CLNS */ | |
341 | #if INET | |
342 | { AF_INET, in_putnetaddr, in_getnetaddr, in_cmpnetaddr, | |
343 | in_putsufx, in_getsufx, | |
344 | in_recycle_tsuffix, | |
345 | tpip_mtu, in_pcbbind, in_pcbconnect, | |
346 | in_pcbdisconnect, in_pcbdetach, | |
347 | in_pcballoc, | |
348 | tpip_output, tpip_output_dg, /* nl_ctloutput */ NULL, | |
349 | (caddr_t) &tp_inpcb, | |
350 | }, | |
351 | #else | |
352 | { 0 }, | |
353 | #endif /* INET */ | |
354 | /* ISO_CONS */ | |
355 | #if defined(ISO) && defined(TPCONS) | |
356 | { AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr, | |
357 | iso_putsufx, iso_getsufx, | |
358 | iso_recycle_tsuffix, | |
359 | tpclnp_mtu, iso_pcbbind, tpcons_pcbconnect, | |
360 | iso_pcbdisconnect, iso_pcbdetach, | |
361 | iso_pcballoc, | |
362 | tpcons_output, tpcons_output, iso_nlctloutput, | |
363 | (caddr_t) &tp_isopcb, | |
364 | }, | |
365 | #else | |
366 | { 0 }, | |
367 | #endif /* ISO_CONS */ | |
368 | /* End of protosw marker */ | |
369 | { 0 } | |
370 | }; | |
371 | ||
372 | u_long tp_sendspace = 1024 * 4; | |
373 | u_long tp_recvspace = 1024 * 4; | |
374 | ||
375 | /* | |
376 | * NAME: tp_init() | |
377 | * | |
378 | * CALLED FROM: | |
379 | * autoconf through the protosw structure | |
380 | * | |
381 | * FUNCTION: | |
382 | * initialize tp machine | |
383 | * | |
384 | * RETURNS: Nada | |
385 | * | |
386 | * SIDE EFFECTS: | |
387 | * | |
388 | * NOTES: | |
389 | */ | |
390 | int | |
391 | tp_init() | |
392 | { | |
393 | static int init_done=0; | |
394 | void tp_timerinit(); | |
395 | ||
396 | if (init_done++) | |
397 | return 0; | |
398 | ||
399 | ||
400 | /* FOR INET */ | |
401 | tp_inpcb.inp_next = tp_inpcb.inp_prev = &tp_inpcb; | |
402 | /* FOR ISO */ | |
403 | tp_isopcb.isop_next = tp_isopcb.isop_prev = &tp_isopcb; | |
404 | ||
405 | tp_start_win = 2; | |
406 | ||
407 | tp_timerinit(); | |
408 | bzero((caddr_t)&tp_stat, sizeof(struct tp_stat)); | |
409 | return 0; | |
410 | } | |
411 | ||
412 | /* | |
413 | * NAME: tp_soisdisconnecting() | |
414 | * | |
415 | * CALLED FROM: | |
416 | * tp.trans | |
417 | * | |
418 | * FUNCTION and ARGUMENTS: | |
419 | * Set state of the socket (so) to reflect that fact that we're disconnectING | |
420 | * | |
421 | * RETURNS: Nada | |
422 | * | |
423 | * SIDE EFFECTS: | |
424 | * | |
425 | * NOTES: | |
426 | * This differs from the regular soisdisconnecting() in that the latter | |
427 | * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags. | |
428 | * We don't want to set those flags because those flags will cause | |
429 | * a SIGPIPE to be delivered in sosend() and we don't like that. | |
430 | * If anyone else is sleeping on this socket, wake 'em up. | |
431 | */ | |
432 | void | |
433 | tp_soisdisconnecting(so) | |
434 | register struct socket *so; | |
435 | { | |
436 | soisdisconnecting(so); | |
437 | so->so_state &= ~SS_CANTSENDMORE; | |
438 | IFPERF(sototpcb(so)) | |
439 | register struct tp_pcb *tpcb = sototpcb(so); | |
440 | u_int fsufx, lsufx; | |
441 | ||
442 | bcopy ((caddr_t)tpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) ); | |
443 | bcopy ((caddr_t)tpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) ); | |
444 | ||
445 | tpmeas(tpcb->tp_lref, TPtime_close, &time, fsufx, lsufx, tpcb->tp_fref); | |
446 | tpcb->tp_perf_on = 0; /* turn perf off */ | |
447 | ENDPERF | |
448 | } | |
449 | ||
450 | ||
451 | /* | |
452 | * NAME: tp_soisdisconnected() | |
453 | * | |
454 | * CALLED FROM: | |
455 | * tp.trans | |
456 | * | |
457 | * FUNCTION and ARGUMENTS: | |
458 | * Set state of the socket (so) to reflect that fact that we're disconnectED | |
459 | * Set the state of the reference structure to closed, and | |
460 | * recycle the suffix. | |
461 | * Start a reference timer. | |
462 | * | |
463 | * RETURNS: Nada | |
464 | * | |
465 | * SIDE EFFECTS: | |
466 | * | |
467 | * NOTES: | |
468 | * This differs from the regular soisdisconnected() in that the latter | |
469 | * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags. | |
470 | * We don't want to set those flags because those flags will cause | |
471 | * a SIGPIPE to be delivered in sosend() and we don't like that. | |
472 | * If anyone else is sleeping on this socket, wake 'em up. | |
473 | */ | |
474 | void | |
475 | tp_soisdisconnected(tpcb) | |
476 | register struct tp_pcb *tpcb; | |
477 | { | |
478 | register struct socket *so = tpcb->tp_sock; | |
479 | ||
480 | soisdisconnecting(so); | |
481 | so->so_state &= ~SS_CANTSENDMORE; | |
482 | IFPERF(tpcb) | |
483 | register struct tp_pcb *ttpcb = sototpcb(so); | |
484 | u_int fsufx, lsufx; | |
485 | ||
486 | /* CHOKE */ | |
487 | bcopy ((caddr_t)ttpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) ); | |
488 | bcopy ((caddr_t)ttpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) ); | |
489 | ||
490 | tpmeas(ttpcb->tp_lref, TPtime_close, | |
491 | &time, &lsufx, &fsufx, ttpcb->tp_fref); | |
492 | tpcb->tp_perf_on = 0; /* turn perf off */ | |
493 | ENDPERF | |
494 | ||
495 | tpcb->tp_refstate = REF_FROZEN; | |
496 | tp_recycle_tsuffix(tpcb); | |
497 | tp_etimeout(tpcb, TM_reference, (int)tpcb->tp_refer_ticks); | |
498 | } | |
499 | ||
500 | /* | |
501 | * NAME: tp_freeref() | |
502 | * | |
503 | * CALLED FROM: | |
504 | * tp.trans when the reference timer goes off, and | |
505 | * from tp_attach() and tp_detach() when a tpcb is partially set up but not | |
506 | * set up enough to have a ref timer set for it, and it's discarded | |
507 | * due to some sort of error or an early close() | |
508 | * | |
509 | * FUNCTION and ARGUMENTS: | |
510 | * Frees the reference represented by (r) for re-use. | |
511 | * | |
512 | * RETURNS: Nothing | |
513 | * | |
514 | * SIDE EFFECTS: | |
515 | * | |
516 | * NOTES: better be called at clock priority !!!!! | |
517 | */ | |
518 | void | |
519 | tp_freeref(n) | |
520 | RefNum n; | |
521 | { | |
522 | register struct tp_ref *r = tp_ref + n; | |
523 | register struct tp_pcb *tpcb; | |
524 | ||
525 | tpcb = r->tpr_pcb; | |
526 | IFDEBUG(D_TIMER) | |
527 | printf("tp_freeref called for ref %d pcb %x maxrefopen %d\n", | |
528 | n, tpcb, tp_refinfo.tpr_maxopen); | |
529 | ENDDEBUG | |
530 | IFTRACE(D_TIMER) | |
531 | tptrace(TPPTmisc, "tp_freeref ref maxrefopen pcb", | |
532 | n, tp_refinfo.tpr_maxopen, tpcb, 0); | |
533 | ENDTRACE | |
534 | if (tpcb == 0) | |
535 | return; | |
536 | IFDEBUG(D_CONN) | |
537 | printf("tp_freeref: CLEARING tpr_pcb 0x%x\n", tpcb); | |
538 | ENDDEBUG | |
539 | r->tpr_pcb = (struct tp_pcb *)0; | |
540 | tpcb->tp_refstate = REF_FREE; | |
541 | ||
542 | for (r = tp_ref + tp_refinfo.tpr_maxopen; r > tp_ref; r--) | |
543 | if (r->tpr_pcb) | |
544 | break; | |
545 | tp_refinfo.tpr_maxopen = r - tp_ref; | |
546 | tp_refinfo.tpr_numopen--; | |
547 | ||
548 | IFDEBUG(D_TIMER) | |
549 | printf("tp_freeref ends w/ maxrefopen %d\n", tp_refinfo.tpr_maxopen); | |
550 | ENDDEBUG | |
551 | } | |
552 | ||
553 | /* | |
554 | * NAME: tp_getref() | |
555 | * | |
556 | * CALLED FROM: | |
557 | * tp_attach() | |
558 | * | |
559 | * FUNCTION and ARGUMENTS: | |
560 | * obtains the next free reference and allocates the appropriate | |
561 | * ref structure, links that structure to (tpcb) | |
562 | * | |
563 | * RETURN VALUE: | |
564 | * a reference number | |
565 | * or TP_ENOREF | |
566 | * | |
567 | * SIDE EFFECTS: | |
568 | * | |
569 | * NOTES: | |
570 | */ | |
571 | u_long | |
572 | tp_getref(tpcb) | |
573 | register struct tp_pcb *tpcb; | |
574 | { | |
575 | register struct tp_ref *r, *rlim; | |
576 | register int i; | |
577 | caddr_t obase; | |
578 | unsigned size; | |
579 | ||
580 | if (++tp_refinfo.tpr_numopen < tp_refinfo.tpr_size) | |
581 | for (r = tp_refinfo.tpr_base, rlim = r + tp_refinfo.tpr_size; | |
582 | ++r < rlim; ) /* tp_ref[0] is never used */ | |
583 | if (r->tpr_pcb == 0) | |
584 | goto got_one; | |
585 | /* else have to allocate more space */ | |
586 | ||
587 | obase = (caddr_t)tp_refinfo.tpr_base; | |
588 | size = tp_refinfo.tpr_size * sizeof(struct tp_ref); | |
589 | // r = (struct tp_ref *) malloc(size + size, M_PCB, M_NOWAIT); | |
590 | MALLOC(r, struct tp_ref *, size + size, M_PCB, M_NOWAIT); | |
591 | if (r == 0) | |
592 | return (--tp_refinfo.tpr_numopen, TP_ENOREF); | |
593 | tp_refinfo.tpr_base = tp_ref = r; | |
594 | tp_refinfo.tpr_size *= 2; | |
595 | bcopy(obase, (caddr_t)r, size); | |
596 | FREE(obase, M_PCB); | |
597 | r = (struct tp_ref *)(size + (caddr_t)r); | |
598 | bzero((caddr_t)r, size); | |
599 | ||
600 | got_one: | |
601 | r->tpr_pcb = tpcb; | |
602 | tpcb->tp_refstate = REF_OPENING; | |
603 | i = r - tp_refinfo.tpr_base; | |
604 | if (tp_refinfo.tpr_maxopen < i) | |
605 | tp_refinfo.tpr_maxopen = i; | |
606 | return (u_long)i; | |
607 | } | |
608 | ||
609 | /* | |
610 | * NAME: tp_set_npcb() | |
611 | * | |
612 | * CALLED FROM: | |
613 | * tp_attach(), tp_route_to() | |
614 | * | |
615 | * FUNCTION and ARGUMENTS: | |
616 | * given a tpcb, allocate an appropriate lower-lever npcb, freeing | |
617 | * any old ones that might need re-assigning. | |
618 | */ | |
619 | tp_set_npcb(tpcb) | |
620 | register struct tp_pcb *tpcb; | |
621 | { | |
622 | register struct socket *so = tpcb->tp_sock; | |
623 | int error; | |
624 | ||
625 | if (tpcb->tp_nlproto && tpcb->tp_npcb) { | |
626 | short so_state = so->so_state; | |
627 | so->so_state &= ~SS_NOFDREF; | |
628 | tpcb->tp_nlproto->nlp_pcbdetach(tpcb->tp_npcb); | |
629 | so->so_state = so_state; | |
630 | } | |
631 | tpcb->tp_nlproto = &nl_protosw[tpcb->tp_netservice]; | |
632 | /* xx_pcballoc sets so_pcb */ | |
633 | error = tpcb->tp_nlproto->nlp_pcballoc(so, tpcb->tp_nlproto->nlp_pcblist); | |
634 | tpcb->tp_npcb = so->so_pcb; | |
635 | so->so_pcb = (caddr_t)tpcb; | |
636 | return (error); | |
637 | } | |
638 | /* | |
639 | * NAME: tp_attach() | |
640 | * | |
641 | * CALLED FROM: | |
642 | * tp_usrreq, PRU_ATTACH | |
643 | * | |
644 | * FUNCTION and ARGUMENTS: | |
645 | * given a socket (so) and a protocol family (dom), allocate a tpcb | |
646 | * and ref structure, initialize everything in the structures that | |
647 | * needs to be initialized. | |
648 | * | |
649 | * RETURN VALUE: | |
650 | * 0 ok | |
651 | * EINVAL if DEBUG(X) in is on and a disaster has occurred | |
652 | * ENOPROTOOPT if TP hasn't been configured or if the | |
653 | * socket wasn't created with tp as its protocol | |
654 | * EISCONN if this socket is already part of a connection | |
655 | * ETOOMANYREFS if ran out of tp reference numbers. | |
656 | * E* whatever error is returned from soreserve() | |
657 | * for from the network-layer pcb allocation routine | |
658 | * | |
659 | * SIDE EFFECTS: | |
660 | * | |
661 | * NOTES: | |
662 | */ | |
663 | tp_attach(so, protocol) | |
664 | struct socket *so; | |
665 | int protocol; | |
666 | { | |
667 | register struct tp_pcb *tpcb; | |
668 | int error = 0; | |
669 | int dom = so->so_proto->pr_domain->dom_family; | |
670 | u_long lref; | |
671 | extern struct tp_conn_param tp_conn_param[]; | |
672 | ||
673 | IFDEBUG(D_CONN) | |
674 | printf("tp_attach:dom 0x%x so 0x%x ", dom, so); | |
675 | ENDDEBUG | |
676 | IFTRACE(D_CONN) | |
677 | tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0); | |
678 | ENDTRACE | |
679 | ||
680 | if (so->so_pcb != NULL) { | |
681 | return EISCONN; /* socket already part of a connection*/ | |
682 | } | |
683 | ||
684 | if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) | |
685 | error = soreserve(so, tp_sendspace, tp_recvspace); | |
686 | /* later an ioctl will allow reallocation IF still in closed state */ | |
687 | ||
688 | if (error) | |
689 | goto bad2; | |
690 | ||
691 | MALLOC(tpcb, struct tp_pcb *, sizeof(*tpcb), M_PCB, M_NOWAIT); | |
692 | if (tpcb == NULL) { | |
693 | error = ENOBUFS; | |
694 | goto bad2; | |
695 | } | |
696 | bzero( (caddr_t)tpcb, sizeof (struct tp_pcb) ); | |
697 | ||
698 | if ( ((lref = tp_getref(tpcb)) & TP_ENOREF) != 0 ) { | |
699 | error = ETOOMANYREFS; | |
700 | goto bad3; | |
701 | } | |
702 | tpcb->tp_lref = lref; | |
703 | tpcb->tp_sock = so; | |
704 | tpcb->tp_domain = dom; | |
705 | tpcb->tp_rhiwat = so->so_rcv.sb_hiwat; | |
706 | /* tpcb->tp_proto = protocol; someday maybe? */ | |
707 | if (protocol && protocol<ISOPROTO_TP4) { | |
708 | tpcb->tp_netservice = ISO_CONS; | |
709 | tpcb->tp_snduna = (SeqNum) -1;/* kludge so the pseudo-ack from the CR/CC | |
710 | * will generate correct fake-ack values | |
711 | */ | |
712 | } else { | |
713 | tpcb->tp_netservice = (dom== AF_INET)?IN_CLNS:ISO_CLNS; | |
714 | /* the default */ | |
715 | } | |
716 | tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice]; | |
717 | ||
718 | tpcb->tp_state = TP_CLOSED; | |
719 | tpcb->tp_vers = TP_VERSION; | |
720 | tpcb->tp_notdetached = 1; | |
721 | ||
722 | /* Spec says default is 128 octets, | |
723 | * that is, if the tpdusize argument never appears, use 128. | |
724 | * As the initiator, we will always "propose" the 2048 | |
725 | * size, that is, we will put this argument in the CR | |
726 | * always, but accept what the other side sends on the CC. | |
727 | * If the initiator sends us something larger on a CR, | |
728 | * we'll respond w/ this. | |
729 | * Our maximum is 4096. See tp_chksum.c comments. | |
730 | */ | |
731 | tpcb->tp_cong_win = | |
732 | tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize; | |
733 | ||
734 | tpcb->tp_seqmask = TP_NML_FMT_MASK; | |
735 | tpcb->tp_seqbit = TP_NML_FMT_BIT; | |
736 | tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1; | |
737 | ||
738 | /* attach to a network-layer protoswitch */ | |
739 | if ( error = tp_set_npcb(tpcb)) | |
740 | goto bad4; | |
741 | ASSERT( tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain); | |
742 | ||
743 | /* nothing to do for iso case */ | |
744 | if( dom == AF_INET ) | |
745 | sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb; | |
746 | ||
747 | return 0; | |
748 | ||
749 | bad4: | |
750 | IFDEBUG(D_CONN) | |
751 | printf("BAD4 in tp_attach, so 0x%x\n", so); | |
752 | ENDDEBUG | |
753 | tp_freeref(tpcb->tp_lref); | |
754 | ||
755 | bad3: | |
756 | IFDEBUG(D_CONN) | |
757 | printf("BAD3 in tp_attach, so 0x%x\n", so); | |
758 | ENDDEBUG | |
759 | ||
760 | FREE((caddr_t)tpcb, M_PCB); /* never a cluster */ | |
761 | ||
762 | bad2: | |
763 | IFDEBUG(D_CONN) | |
764 | printf("BAD2 in tp_attach, so 0x%x\n", so); | |
765 | ENDDEBUG | |
766 | so->so_pcb = 0; | |
767 | ||
768 | /*bad:*/ | |
769 | IFDEBUG(D_CONN) | |
770 | printf("BAD in tp_attach, so 0x%x\n", so); | |
771 | ENDDEBUG | |
772 | return error; | |
773 | } | |
774 | ||
775 | /* | |
776 | * NAME: tp_detach() | |
777 | * | |
778 | * CALLED FROM: | |
779 | * tp.trans, on behalf of a user close request | |
780 | * and when the reference timer goes off | |
781 | * (if the disconnect was initiated by the protocol entity | |
782 | * rather than by the user) | |
783 | * | |
784 | * FUNCTION and ARGUMENTS: | |
785 | * remove the tpcb structure from the list of active or | |
786 | * partially active connections, recycle all the mbufs | |
787 | * associated with the pcb, ref structure, sockbufs, etc. | |
788 | * Only free the ref structure if you know that a ref timer | |
789 | * wasn't set for this tpcb. | |
790 | * | |
791 | * RETURNS: Nada | |
792 | * | |
793 | * SIDE EFFECTS: | |
794 | * | |
795 | * NOTES: | |
796 | * tp_soisdisconnected() was already when this is called | |
797 | */ | |
798 | void | |
799 | tp_detach(tpcb) | |
800 | register struct tp_pcb *tpcb; | |
801 | { | |
802 | void tp_freeref(), tp_rsyflush(); | |
803 | register struct socket *so = tpcb->tp_sock; | |
804 | ||
805 | IFDEBUG(D_CONN) | |
806 | printf("tp_detach(tpcb 0x%x, so 0x%x)\n", | |
807 | tpcb,so); | |
808 | ENDDEBUG | |
809 | IFTRACE(D_CONN) | |
810 | tptraceTPCB(TPPTmisc, "tp_detach tpcb so lsufx", | |
811 | tpcb, so, *(u_short *)(tpcb->tp_lsuffix), 0); | |
812 | ENDTRACE | |
813 | ||
814 | IFDEBUG(D_CONN) | |
815 | printf("so_snd at 0x%x so_rcv at 0x%x\n", &so->so_snd, &so->so_rcv); | |
816 | dump_mbuf(so->so_snd.sb_mb, "so_snd at detach "); | |
817 | printf("about to call LL detach, nlproto 0x%x, nl_detach 0x%x\n", | |
818 | tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach); | |
819 | ENDDEBUG | |
820 | ||
821 | if (tpcb->tp_Xsnd.sb_mb) { | |
822 | printf("Unsent Xdata on detach; would panic"); | |
823 | sbflush(&tpcb->tp_Xsnd); | |
824 | } | |
825 | if (tpcb->tp_ucddata) | |
826 | m_freem(tpcb->tp_ucddata); | |
827 | ||
828 | IFDEBUG(D_CONN) | |
829 | printf("reassembly info cnt %d rsyq 0x%x\n", | |
830 | tpcb->tp_rsycnt, tpcb->tp_rsyq); | |
831 | ENDDEBUG | |
832 | if (tpcb->tp_rsyq) | |
833 | tp_rsyflush(tpcb); | |
834 | ||
835 | if (tpcb->tp_next) { | |
836 | remque(tpcb); | |
837 | tpcb->tp_next = tpcb->tp_prev = 0; | |
838 | } | |
839 | tpcb->tp_notdetached = 0; | |
840 | ||
841 | IFDEBUG(D_CONN) | |
842 | printf("calling (...nlproto->...)(0x%x, so 0x%x)\n", | |
843 | tpcb->tp_npcb, so); | |
844 | printf("so 0x%x so_head 0x%x, qlen %d q0len %d qlimit %d\n", | |
845 | so, so->so_head, | |
846 | so->so_q0len, so->so_qlen, so->so_qlimit); | |
847 | ENDDEBUG | |
848 | ||
849 | (tpcb->tp_nlproto->nlp_pcbdetach)(tpcb->tp_npcb); | |
850 | /* does an so->so_pcb = 0; sofree(so) */ | |
851 | ||
852 | IFDEBUG(D_CONN) | |
853 | printf("after xxx_pcbdetach\n"); | |
854 | ENDDEBUG | |
855 | ||
856 | if (tpcb->tp_state == TP_LISTENING) { | |
857 | register struct tp_pcb **tt; | |
858 | for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten)) | |
859 | if (*tt == tpcb) | |
860 | break; | |
861 | if (*tt) | |
862 | *tt = tpcb->tp_nextlisten; | |
863 | else | |
864 | printf("tp_detach from listen: should panic\n"); | |
865 | } | |
866 | if (tpcb->tp_refstate == REF_OPENING ) { | |
867 | /* no connection existed here so no reference timer will be called */ | |
868 | IFDEBUG(D_CONN) | |
869 | printf("SETTING ref %d to REF_FREE\n", tpcb->tp_lref); | |
870 | ENDDEBUG | |
871 | ||
872 | tp_freeref(tpcb->tp_lref); | |
873 | } | |
874 | #ifdef TP_PERF_MEAS | |
875 | /* | |
876 | * Get rid of the cluster mbuf allocated for performance measurements, if | |
877 | * there is one. Note that tpcb->tp_perf_on says nothing about whether or | |
878 | * not a cluster mbuf was allocated, so you have to check for a pointer | |
879 | * to one (that is, we need the TP_PERF_MEASs around the following section | |
880 | * of code, not the IFPERFs) | |
881 | */ | |
882 | if (tpcb->tp_p_mbuf) { | |
883 | register struct mbuf *m = tpcb->tp_p_mbuf; | |
884 | struct mbuf *n; | |
885 | IFDEBUG(D_PERF_MEAS) | |
886 | printf("freeing tp_p_meas 0x%x ", tpcb->tp_p_meas); | |
887 | ENDDEBUG | |
888 | do { | |
889 | MFREE(m, n); | |
890 | m = n; | |
891 | } while (n); | |
892 | tpcb->tp_p_meas = 0; | |
893 | tpcb->tp_p_mbuf = 0; | |
894 | } | |
895 | #endif /* TP_PERF_MEAS */ | |
896 | ||
897 | IFDEBUG(D_CONN) | |
898 | printf( "end of detach, NOT single, tpcb 0x%x\n", tpcb); | |
899 | ENDDEBUG | |
900 | /* FREE((caddr_t)tpcb, M_PCB); WHere to put this ? */ | |
901 | } | |
902 | ||
903 | struct que { | |
904 | struct tp_pcb *next; | |
905 | struct tp_pcb *prev; | |
906 | } tp_bound_pcbs = | |
907 | {(struct tp_pcb *)&tp_bound_pcbs, (struct tp_pcb *)&tp_bound_pcbs}; | |
908 | ||
909 | u_short tp_unique; | |
910 | ||
911 | tp_tselinuse(tlen, tsel, siso, reuseaddr) | |
912 | caddr_t tsel; | |
913 | register struct sockaddr_iso *siso; | |
914 | { | |
915 | struct tp_pcb *b = tp_bound_pcbs.next, *l = tp_listeners; | |
916 | register struct tp_pcb *t; | |
917 | ||
918 | for (;;) { | |
919 | if (b != (struct tp_pcb *)&tp_bound_pcbs) { | |
920 | t = b; b = t->tp_next; | |
921 | } else if (l) { | |
922 | t = l; l = t->tp_nextlisten; | |
923 | } else | |
924 | break; | |
925 | if (tlen == t->tp_lsuffixlen && bcmp(tsel, t->tp_lsuffix, tlen) == 0) { | |
926 | if (t->tp_flags & TPF_GENERAL_ADDR) { | |
927 | if (siso == 0 || reuseaddr == 0) | |
928 | return 1; | |
929 | } else if (siso) { | |
930 | if (siso->siso_family == t->tp_domain && | |
931 | t->tp_nlproto->nlp_cmpnetaddr(t->tp_npcb, siso, TP_LOCAL)) | |
932 | return 1; | |
933 | } else if (reuseaddr == 0) | |
934 | return 1; | |
935 | } | |
936 | } | |
937 | return 0; | |
938 | ||
939 | } | |
940 | ||
941 | ||
942 | tp_pcbbind(tpcb, nam) | |
943 | register struct tp_pcb *tpcb; | |
944 | register struct mbuf *nam; | |
945 | { | |
946 | register struct sockaddr_iso *siso = 0; | |
947 | int tlen = 0, wrapped = 0; | |
948 | caddr_t tsel; | |
949 | u_short tutil; | |
950 | ||
951 | if (tpcb->tp_state != TP_CLOSED) | |
952 | return (EINVAL); | |
953 | if (nam) { | |
954 | siso = mtod(nam, struct sockaddr_iso *); | |
955 | switch (siso->siso_family) { | |
956 | default: | |
957 | return (EAFNOSUPPORT); | |
958 | #if ISO | |
959 | case AF_ISO: | |
960 | tlen = siso->siso_tlen; | |
961 | tsel = TSEL(siso); | |
962 | if (siso->siso_nlen == 0) | |
963 | siso = 0; | |
964 | break; | |
965 | #endif | |
966 | #if INET | |
967 | case AF_INET: | |
968 | tsel = (caddr_t)&tutil; | |
969 | if (tutil = ((struct sockaddr_in *)siso)->sin_port) { | |
970 | tlen = 2; | |
971 | } | |
972 | if (((struct sockaddr_in *)siso)->sin_addr.s_addr == 0) | |
973 | siso = 0; | |
974 | } | |
975 | #endif | |
976 | } | |
977 | if (tpcb->tp_lsuffixlen == 0) { | |
978 | if (tlen) { | |
979 | if (tp_tselinuse(tlen, tsel, siso, | |
980 | tpcb->tp_sock->so_options & SO_REUSEADDR)) | |
981 | return (EINVAL); | |
982 | } else { | |
983 | for (tsel = (caddr_t)&tutil, tlen = 2;;){ | |
984 | if (tp_unique++ < ISO_PORT_RESERVED || | |
985 | tp_unique > ISO_PORT_USERRESERVED) { | |
986 | if (wrapped++) | |
987 | return ESRCH; | |
988 | tp_unique = ISO_PORT_RESERVED; | |
989 | } | |
990 | tutil = htons(tp_unique); | |
991 | if (tp_tselinuse(tlen, tsel, siso, 0) == 0) | |
992 | break; | |
993 | } | |
994 | if (siso) switch (siso->siso_family) { | |
995 | #if ISO | |
996 | case AF_ISO: | |
997 | bcopy(tsel, TSEL(siso), tlen); | |
998 | siso->siso_tlen = tlen; | |
999 | break; | |
1000 | #endif | |
1001 | #if INET | |
1002 | case AF_INET: | |
1003 | ((struct sockaddr_in *)siso)->sin_port = tutil; | |
1004 | #endif | |
1005 | } | |
1006 | } | |
1007 | bcopy(tsel, tpcb->tp_lsuffix, (tpcb->tp_lsuffixlen = tlen)); | |
1008 | insque(tpcb, &tp_bound_pcbs); | |
1009 | } else { | |
1010 | if (tlen || siso == 0) | |
1011 | return (EINVAL); | |
1012 | } | |
1013 | if (siso == 0) { | |
1014 | tpcb->tp_flags |= TPF_GENERAL_ADDR; | |
1015 | return (0); | |
1016 | } | |
1017 | return tpcb->tp_nlproto->nlp_pcbbind(tpcb->tp_npcb, nam); | |
1018 | } |