Commit | Line | Data |
---|---|---|
c32c2ec1 | 1 | /*********************************************************** |
7b25382f | 2 | Copyright IBM Corporation 1987 |
c32c2ec1 KS |
3 | |
4 | All Rights Reserved | |
5 | ||
6 | Permission to use, copy, modify, and distribute this software and its | |
7 | documentation for any purpose and without fee is hereby granted, | |
8 | provided that the above copyright notice appear in all copies and that | |
9 | both that copyright notice and this permission notice appear in | |
10 | supporting documentation, and that the name of IBM not be | |
11 | used in advertising or publicity pertaining to distribution of the | |
12 | software without specific, written prior permission. | |
13 | ||
14 | IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING | |
15 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL | |
16 | IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR | |
17 | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
18 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
19 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
20 | SOFTWARE. | |
21 | ||
22 | ******************************************************************/ | |
23 | ||
24 | /* | |
25 | * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison | |
26 | */ | |
27 | /* | |
28 | * ARGO TP | |
29 | * | |
30 | * $Header: tp_pcb.c,v 5.4 88/11/18 17:28:24 nhall Exp $ | |
31 | * $Source: /usr/argo/sys/netiso/RCS/tp_pcb.c,v $ | |
194a383a | 32 | * @(#)tp_pcb.c 7.7 (Berkeley) %G% * |
c32c2ec1 KS |
33 | * |
34 | * | |
35 | * This is the initialization and cleanup stuff - | |
36 | * for the tp machine in general as well as for the individual pcbs. | |
37 | * tp_init() is called at system startup. tp_attach() and tp_getref() are | |
38 | * called when a socket is created. tp_detach() and tp_freeref() | |
39 | * are called during the closing stage and/or when the reference timer | |
40 | * goes off. | |
41 | * tp_soisdisconnecting() and tp_soisdisconnected() are tp-specific | |
42 | * versions of soisconnect* | |
43 | * and are called (obviously) during the closing phase. | |
44 | * | |
45 | */ | |
46 | ||
47 | #ifndef lint | |
48 | static char *rcsid = "$Header: tp_pcb.c,v 5.4 88/11/18 17:28:24 nhall Exp $"; | |
49 | #endif lint | |
50 | ||
c32c2ec1 KS |
51 | #include "types.h" |
52 | #include "param.h" | |
53 | #include "mbuf.h" | |
54 | #include "socket.h" | |
55 | #include "socketvar.h" | |
56 | #include "protosw.h" | |
57 | #include "errno.h" | |
58 | #include "time.h" | |
a50e2bc0 KS |
59 | #include "argo_debug.h" |
60 | #include "tp_param.h" | |
61 | #include "tp_timer.h" | |
62 | #include "tp_ip.h" | |
63 | #include "tp_stat.h" | |
64 | #include "tp_pcb.h" | |
65 | #include "tp_tpdu.h" | |
66 | #include "tp_trace.h" | |
67 | #include "tp_meas.h" | |
68 | #include "tp_seq.h" | |
69 | #include "tp_clnp.h" | |
c32c2ec1 KS |
70 | |
71 | /* list of reference structures */ | |
72 | struct tp_ref tp_ref[N_TPREF]; | |
73 | ||
74 | struct tp_param tp_param = { | |
75 | 1, /* configured */ | |
76 | }; | |
77 | ||
78 | /* ticks are in units of: | |
79 | * 500 nano-fortnights ;-) or | |
80 | * 500 ms or | |
81 | * 1/2 second | |
82 | */ | |
83 | ||
84 | struct tp_conn_param tp_conn_param[] = { | |
85 | /* ISO_CLNS: TP4 CONNECTION LESS */ | |
86 | { | |
87 | TP_NRETRANS, /* short p_Nretrans; */ | |
88 | 20, /* 10 sec */ /* short p_dr_ticks; */ | |
89 | ||
90 | 20, /* 10 sec */ /* short p_cc_ticks; */ | |
91 | 20, /* 10 sec */ /* short p_dt_ticks; */ | |
92 | ||
93 | 40, /* 20 sec */ /* short p_x_ticks; */ | |
94 | 80, /* 40 sec */ /* short p_cr_ticks;*/ | |
95 | ||
96 | 240, /* 2 min */ /* short p_keepalive_ticks;*/ | |
97 | 10, /* 5 sec */ /* short p_sendack_ticks; */ | |
98 | ||
99 | 600, /* 5 min */ /* short p_ref_ticks; */ | |
100 | 360, /* 3 min */ /* short p_inact_ticks; */ | |
101 | ||
102 | (short) 100, /* short p_lcdtfract */ | |
103 | (short) TP_SOCKBUFSIZE, /* short p_winsize */ | |
104 | TP_TPDUSIZE, /* u_char p_tpdusize */ | |
105 | ||
106 | TPACK_WINDOW, /* 4 bits p_ack_strat */ | |
107 | TPRX_USE_CW | TPRX_FASTSTART, | |
108 | /* 4 bits p_rx_strat*/ | |
109 | TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */ | |
110 | 1, /* 1 bit xtd format */ | |
111 | 1, /* 1 bit xpd service */ | |
112 | 1, /* 1 bit use_checksum */ | |
113 | 0, /* 1 bit use net xpd */ | |
114 | 0, /* 1 bit use rcc */ | |
115 | 0, /* 1 bit use efc */ | |
44f52ea5 | 116 | 1, /* no disc indications */ |
c32c2ec1 KS |
117 | 0, /* don't change params */ |
118 | ISO_CLNS, /* p_netservice */ | |
119 | }, | |
120 | /* IN_CLNS: TP4 CONNECTION LESS */ | |
121 | { | |
122 | TP_NRETRANS, /* short p_Nretrans; */ | |
123 | 20, /* 10 sec */ /* short p_dr_ticks; */ | |
124 | ||
125 | 20, /* 10 sec */ /* short p_cc_ticks; */ | |
126 | 20, /* 10 sec */ /* short p_dt_ticks; */ | |
127 | ||
128 | 40, /* 20 sec */ /* short p_x_ticks; */ | |
129 | 80, /* 40 sec */ /* short p_cr_ticks;*/ | |
130 | ||
131 | 240, /* 2 min */ /* short p_keepalive_ticks;*/ | |
132 | 10, /* 5 sec */ /* short p_sendack_ticks; */ | |
133 | ||
134 | 600, /* 5 min */ /* short p_ref_ticks; */ | |
135 | 360, /* 3 min */ /* short p_inact_ticks; */ | |
136 | ||
137 | (short) 100, /* short p_lcdtfract */ | |
138 | (short) TP_SOCKBUFSIZE, /* short p_winsize */ | |
139 | TP_TPDUSIZE, /* u_char p_tpdusize */ | |
140 | ||
141 | TPACK_WINDOW, /* 4 bits p_ack_strat */ | |
142 | TPRX_USE_CW | TPRX_FASTSTART, | |
143 | /* 4 bits p_rx_strat*/ | |
144 | TP_CLASS_4, /* 5 bits p_class */ | |
145 | 1, /* 1 bit xtd format */ | |
146 | 1, /* 1 bit xpd service */ | |
147 | 1, /* 1 bit use_checksum */ | |
148 | 0, /* 1 bit use net xpd */ | |
149 | 0, /* 1 bit use rcc */ | |
150 | 0, /* 1 bit use efc */ | |
44f52ea5 | 151 | 1, /* no disc indications */ |
c32c2ec1 KS |
152 | 0, /* don't change params */ |
153 | IN_CLNS, /* p_netservice */ | |
154 | }, | |
155 | /* ISO_CONS: TP0 CONNECTION MODE */ | |
156 | { | |
157 | TP_NRETRANS, /* short p_Nretrans; */ | |
158 | 0, /* n/a */ /* short p_dr_ticks; */ | |
159 | ||
160 | 40, /* 20 sec */ /* short p_cc_ticks; */ | |
161 | 0, /* n/a */ /* short p_dt_ticks; */ | |
162 | ||
163 | 0, /* n/a */ /* short p_x_ticks; */ | |
164 | 360, /* 3 min */ /* short p_cr_ticks;*/ | |
165 | ||
166 | 0, /* n/a */ /* short p_keepalive_ticks;*/ | |
167 | 0, /* n/a */ /* short p_sendack_ticks; */ | |
168 | ||
169 | 600, /* for cr/cc to clear *//* short p_ref_ticks; */ | |
170 | 0, /* n/a */ /* short p_inact_ticks; */ | |
171 | ||
172 | /* Use tp4 defaults just in case the user changes ONLY | |
173 | * the class | |
174 | */ | |
175 | (short) 100, /* short p_lcdtfract */ | |
176 | (short) TP0_SOCKBUFSIZE, /* short p_winsize */ | |
177 | TP0_TPDUSIZE, /* 8 bits p_tpdusize */ | |
178 | ||
179 | 0, /* 4 bits p_ack_strat */ | |
180 | 0, /* 4 bits p_rx_strat*/ | |
181 | TP_CLASS_0, /* 5 bits p_class */ | |
182 | 0, /* 1 bit xtd format */ | |
183 | 0, /* 1 bit xpd service */ | |
184 | 0, /* 1 bit use_checksum */ | |
185 | 0, /* 1 bit use net xpd */ | |
186 | 0, /* 1 bit use rcc */ | |
187 | 0, /* 1 bit use efc */ | |
188 | 0, /* no disc indications */ | |
189 | 0, /* don't change params */ | |
190 | ISO_CONS, /* p_netservice */ | |
191 | }, | |
192 | /* ISO_COSNS: TP4 CONNECTION LESS SERVICE over CONSNS */ | |
193 | { | |
194 | TP_NRETRANS, /* short p_Nretrans; */ | |
195 | 40, /* 20 sec */ /* short p_dr_ticks; */ | |
196 | ||
197 | 40, /* 20 sec */ /* short p_cc_ticks; */ | |
198 | 80, /* 40 sec */ /* short p_dt_ticks; */ | |
199 | ||
200 | 120, /* 1 min */ /* short p_x_ticks; */ | |
201 | 360, /* 3 min */ /* short p_cr_ticks;*/ | |
202 | ||
203 | 360, /* 3 min */ /* short p_keepalive_ticks;*/ | |
204 | 20, /* 10 sec */ /* short p_sendack_ticks; */ | |
205 | ||
206 | 600, /* 5 min */ /* short p_ref_ticks; */ | |
207 | 480, /* 4 min */ /* short p_inact_ticks; */ | |
208 | ||
209 | (short) 100, /* short p_lcdtfract */ | |
210 | (short) TP0_SOCKBUFSIZE, /* short p_winsize */ | |
211 | TP0_TPDUSIZE, /* u_char p_tpdusize */ | |
212 | ||
213 | TPACK_WINDOW, /* 4 bits p_ack_strat */ | |
214 | TPRX_USE_CW , /* No fast start */ | |
215 | /* 4 bits p_rx_strat*/ | |
216 | TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */ | |
217 | 0, /* 1 bit xtd format */ | |
218 | 1, /* 1 bit xpd service */ | |
219 | 1, /* 1 bit use_checksum */ | |
220 | 0, /* 1 bit use net xpd */ | |
221 | 0, /* 1 bit use rcc */ | |
222 | 0, /* 1 bit use efc */ | |
223 | 0, /* no disc indications */ | |
224 | 0, /* don't change params */ | |
225 | ISO_COSNS, /* p_netservice */ | |
226 | }, | |
227 | }; | |
228 | ||
229 | #ifdef INET | |
230 | int in_putnetaddr(); | |
231 | int in_getnetaddr(); | |
63f88aec | 232 | int in_cmpnetaddr(); |
c32c2ec1 KS |
233 | int in_putsufx(); |
234 | int in_getsufx(); | |
235 | int in_recycle_tsuffix(); | |
236 | int tpip_mtu(); | |
237 | int in_pcbbind(); | |
238 | int in_pcbconnect(); | |
239 | int in_pcbdisconnect(); | |
240 | int in_pcbdetach(); | |
241 | int in_pcballoc(); | |
242 | int tpip_output(); | |
243 | int tpip_output_dg(); | |
244 | struct inpcb tp_inpcb; | |
245 | #endif INET | |
246 | #ifdef ISO | |
247 | int iso_putnetaddr(); | |
248 | int iso_getnetaddr(); | |
63f88aec | 249 | int iso_cmpnetaddr(); |
c32c2ec1 KS |
250 | int iso_putsufx(); |
251 | int iso_getsufx(); | |
252 | int iso_recycle_tsuffix(); | |
253 | int tpclnp_mtu(); | |
254 | int iso_pcbbind(); | |
255 | int iso_pcbconnect(); | |
256 | int iso_pcbdisconnect(); | |
257 | int iso_pcbdetach(); | |
258 | int iso_pcballoc(); | |
259 | int tpclnp_output(); | |
260 | int tpclnp_output_dg(); | |
261 | int iso_nlctloutput(); | |
262 | struct isopcb tp_isopcb; | |
263 | #endif ISO | |
194a383a | 264 | #ifdef TPCONS |
c32c2ec1 KS |
265 | int iso_putnetaddr(); |
266 | int iso_getnetaddr(); | |
63f88aec | 267 | int iso_cmpnetaddr(); |
c32c2ec1 KS |
268 | int iso_putsufx(); |
269 | int iso_getsufx(); | |
270 | int iso_recycle_tsuffix(); | |
271 | int tpcons_mtu(); | |
272 | int iso_pcbbind(); | |
194a383a | 273 | int tpcons_pcbconnect(); |
c32c2ec1 KS |
274 | int iso_pcbdisconnect(); |
275 | int iso_pcbdetach(); | |
276 | int iso_pcballoc(); | |
277 | int tpcons_output(); | |
c32c2ec1 | 278 | struct isopcb tp_isopcb; |
194a383a | 279 | #endif TPCONS |
c32c2ec1 | 280 | |
a50e2bc0 | 281 | |
c32c2ec1 KS |
282 | struct nl_protosw nl_protosw[] = { |
283 | /* ISO_CLNS */ | |
284 | #ifdef ISO | |
63f88aec | 285 | { AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr, |
c32c2ec1 KS |
286 | iso_putsufx, iso_getsufx, |
287 | iso_recycle_tsuffix, | |
288 | tpclnp_mtu, iso_pcbbind, iso_pcbconnect, | |
289 | iso_pcbdisconnect, iso_pcbdetach, | |
290 | iso_pcballoc, | |
291 | tpclnp_output, tpclnp_output_dg, iso_nlctloutput, | |
292 | (caddr_t) &tp_isopcb, | |
293 | }, | |
a50e2bc0 KS |
294 | #else |
295 | { 0 }, | |
c32c2ec1 KS |
296 | #endif ISO |
297 | /* IN_CLNS */ | |
298 | #ifdef INET | |
63f88aec | 299 | { AF_INET, in_putnetaddr, in_getnetaddr, in_cmpnetaddr, |
c32c2ec1 KS |
300 | in_putsufx, in_getsufx, |
301 | in_recycle_tsuffix, | |
302 | tpip_mtu, in_pcbbind, in_pcbconnect, | |
303 | in_pcbdisconnect, in_pcbdetach, | |
304 | in_pcballoc, | |
305 | tpip_output, tpip_output_dg, /* nl_ctloutput */ NULL, | |
306 | (caddr_t) &tp_inpcb, | |
307 | }, | |
a50e2bc0 KS |
308 | #else |
309 | { 0 }, | |
c32c2ec1 KS |
310 | #endif INET |
311 | /* ISO_CONS */ | |
194a383a | 312 | #if defined(ISO) && defined(TPCONS) |
63f88aec | 313 | { AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr, |
c32c2ec1 KS |
314 | iso_putsufx, iso_getsufx, |
315 | iso_recycle_tsuffix, | |
194a383a | 316 | tpcons_mtu, iso_pcbbind, tpcons_pcbconnect, |
c32c2ec1 KS |
317 | iso_pcbdisconnect, iso_pcbdetach, |
318 | iso_pcballoc, | |
194a383a | 319 | tpcons_output, tpcons_output, iso_nlctloutput, |
c32c2ec1 KS |
320 | (caddr_t) &tp_isopcb, |
321 | }, | |
a50e2bc0 KS |
322 | #else |
323 | { 0 }, | |
324 | #endif ISO_CONS | |
325 | /* End of protosw marker */ | |
326 | { 0 } | |
c32c2ec1 KS |
327 | }; |
328 | ||
329 | /* | |
330 | * NAME: tp_init() | |
331 | * | |
332 | * CALLED FROM: | |
333 | * autoconf through the protosw structure | |
334 | * | |
335 | * FUNCTION: | |
336 | * initialize tp machine | |
337 | * | |
338 | * RETURNS: Nada | |
339 | * | |
340 | * SIDE EFFECTS: | |
341 | * | |
342 | * NOTES: | |
343 | */ | |
a50e2bc0 | 344 | int |
c32c2ec1 KS |
345 | tp_init() |
346 | { | |
347 | static int init_done=0; | |
348 | void tp_timerinit(); | |
349 | ||
350 | if (init_done++) | |
a50e2bc0 | 351 | return 0; |
c32c2ec1 | 352 | |
c32c2ec1 KS |
353 | |
354 | /* FOR INET */ | |
355 | tp_inpcb.inp_next = tp_inpcb.inp_prev = &tp_inpcb; | |
356 | /* FOR ISO */ | |
357 | tp_isopcb.isop_next = tp_isopcb.isop_prev = &tp_isopcb; | |
358 | ||
620f4252 KS |
359 | tp_start_win = 2; |
360 | ||
c32c2ec1 KS |
361 | tp_timerinit(); |
362 | bzero((caddr_t)&tp_stat, sizeof(struct tp_stat)); | |
a50e2bc0 | 363 | return 0; |
c32c2ec1 KS |
364 | } |
365 | ||
366 | /* | |
367 | * NAME: tp_soisdisconnecting() | |
368 | * | |
369 | * CALLED FROM: | |
370 | * tp.trans | |
371 | * | |
372 | * FUNCTION and ARGUMENTS: | |
373 | * Set state of the socket (so) to reflect that fact that we're disconnectING | |
374 | * | |
375 | * RETURNS: Nada | |
376 | * | |
377 | * SIDE EFFECTS: | |
378 | * | |
379 | * NOTES: | |
380 | * This differs from the regular soisdisconnecting() in that the latter | |
381 | * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags. | |
382 | * We don't want to set those flags because those flags will cause | |
383 | * a SIGPIPE to be delivered in sosend() and we don't like that. | |
384 | * If anyone else is sleeping on this socket, wake 'em up. | |
385 | */ | |
386 | void | |
387 | tp_soisdisconnecting(so) | |
388 | register struct socket *so; | |
389 | { | |
44f52ea5 KS |
390 | soisdisconnecting(so); |
391 | so->so_state &= ~SS_CANTSENDMORE; | |
c32c2ec1 KS |
392 | IFPERF(sototpcb(so)) |
393 | register struct tp_pcb *tpcb = sototpcb(so); | |
394 | u_int fsufx, lsufx; | |
395 | ||
a50e2bc0 KS |
396 | bcopy ((caddr_t)tpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) ); |
397 | bcopy ((caddr_t)tpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) ); | |
c32c2ec1 | 398 | |
a50e2bc0 | 399 | tpmeas(tpcb->tp_lref, TPtime_close, &time, fsufx, lsufx, tpcb->tp_fref); |
c32c2ec1 KS |
400 | tpcb->tp_perf_on = 0; /* turn perf off */ |
401 | ENDPERF | |
402 | } | |
403 | ||
404 | ||
405 | /* | |
406 | * NAME: tp_soisdisconnected() | |
407 | * | |
408 | * CALLED FROM: | |
409 | * tp.trans | |
410 | * | |
411 | * FUNCTION and ARGUMENTS: | |
412 | * Set state of the socket (so) to reflect that fact that we're disconnectED | |
413 | * Set the state of the reference structure to closed, and | |
414 | * recycle the suffix. | |
415 | * Start a reference timer. | |
416 | * | |
417 | * RETURNS: Nada | |
418 | * | |
419 | * SIDE EFFECTS: | |
420 | * | |
421 | * NOTES: | |
422 | * This differs from the regular soisdisconnected() in that the latter | |
423 | * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags. | |
424 | * We don't want to set those flags because those flags will cause | |
425 | * a SIGPIPE to be delivered in sosend() and we don't like that. | |
426 | * If anyone else is sleeping on this socket, wake 'em up. | |
427 | */ | |
428 | void | |
429 | tp_soisdisconnected(tpcb) | |
430 | register struct tp_pcb *tpcb; | |
431 | { | |
432 | register struct socket *so = tpcb->tp_sock; | |
433 | ||
44f52ea5 KS |
434 | soisdisconnecting(so); |
435 | so->so_state &= ~SS_CANTSENDMORE; | |
c32c2ec1 | 436 | IFPERF(sototpcb(so)) |
a50e2bc0 | 437 | register struct tp_pcb *ttpcb = sototpcb(so); |
c32c2ec1 KS |
438 | u_int fsufx, lsufx; |
439 | ||
440 | /* CHOKE */ | |
a50e2bc0 KS |
441 | bcopy ((caddr_t)ttpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) ); |
442 | bcopy ((caddr_t)ttpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) ); | |
c32c2ec1 | 443 | |
a50e2bc0 KS |
444 | tpmeas(ttpcb->tp_lref, TPtime_close, |
445 | &time, &lsufx, &fsufx, ttpcb->tp_fref); | |
c32c2ec1 KS |
446 | tpcb->tp_perf_on = 0; /* turn perf off */ |
447 | ENDPERF | |
448 | ||
449 | tpcb->tp_refp->tpr_state = REF_FROZEN; | |
450 | tp_recycle_tsuffix( tpcb ); | |
451 | tp_etimeout(tpcb->tp_refp, TM_reference, 0,0,0, (int)tpcb->tp_refer_ticks); | |
452 | } | |
453 | ||
454 | int tp_maxrefopen; /* highest reference # of the set of open tp connections */ | |
455 | ||
456 | /* | |
457 | * NAME: tp_freeref() | |
458 | * | |
459 | * CALLED FROM: | |
460 | * tp.trans when the reference timer goes off, and | |
461 | * from tp_attach() and tp_detach() when a tpcb is partially set up but not | |
462 | * set up enough to have a ref timer set for it, and it's discarded | |
463 | * due to some sort of error or an early close() | |
464 | * | |
465 | * FUNCTION and ARGUMENTS: | |
466 | * Frees the reference represented by (r) for re-use. | |
467 | * | |
468 | * RETURNS: Nothing | |
469 | * | |
470 | * SIDE EFFECTS: | |
471 | * | |
472 | * NOTES: better be called at clock priority !!!!! | |
473 | */ | |
474 | void | |
475 | tp_freeref(r) | |
476 | register struct tp_ref *r; | |
477 | { | |
478 | IFDEBUG(D_TIMER) | |
479 | printf("tp_freeref called for ref %d maxrefopen %d\n", | |
480 | r - tp_ref, tp_maxrefopen); | |
481 | ENDDEBUG | |
482 | IFTRACE(D_TIMER) | |
483 | tptrace(TPPTmisc, "tp_freeref ref tp_maxrefopen", | |
484 | r - tp_ref, tp_maxrefopen, 0, 0); | |
485 | ENDTRACE | |
486 | r->tpr_state = REF_FREE; | |
487 | IFDEBUG(D_CONN) | |
488 | printf("tp_freeref: CLEARING tpr_pcb 0x%x\n", r->tpr_pcb); | |
489 | ENDDEBUG | |
490 | r->tpr_pcb = (struct tp_pcb *)0; | |
491 | ||
492 | r = &tp_ref[tp_maxrefopen]; | |
493 | ||
494 | while( tp_maxrefopen > 0 ) { | |
495 | if(r->tpr_state ) | |
496 | break; | |
497 | tp_maxrefopen--; | |
498 | r--; | |
499 | } | |
500 | IFDEBUG(D_TIMER) | |
501 | printf("tp_freeref ends w/ maxrefopen %d\n", tp_maxrefopen); | |
502 | ENDDEBUG | |
503 | } | |
504 | ||
505 | /* | |
506 | * NAME: tp_getref() | |
507 | * | |
508 | * CALLED FROM: | |
509 | * tp_attach() | |
510 | * | |
511 | * FUNCTION and ARGUMENTS: | |
512 | * obtains the next free reference and allocates the appropriate | |
513 | * ref structure, links that structure to (tpcb) | |
514 | * | |
515 | * RETURN VALUE: | |
516 | * a reference number | |
517 | * or TP_ENOREF | |
518 | * | |
519 | * SIDE EFFECTS: | |
520 | * | |
521 | * NOTES: | |
522 | */ | |
523 | static RefNum | |
524 | tp_getref(tpcb) | |
525 | register struct tp_pcb *tpcb; | |
526 | { | |
527 | register struct tp_ref *r = tp_ref; | |
528 | register int i=1; | |
529 | ||
530 | r++; /* tp_ref[0] is never used */ | |
531 | ||
532 | /* REF_FREE is zero */ | |
533 | while( r->tpr_state ) { | |
534 | r++; | |
535 | if ( i == N_TPREF ) { | |
536 | return TP_ENOREF; | |
537 | } | |
538 | i++; | |
539 | } | |
540 | r->tpr_state = REF_OPENING; | |
541 | if (tp_maxrefopen < i) | |
542 | tp_maxrefopen = i; | |
543 | r->tpr_pcb = tpcb; | |
544 | tpcb->tp_refp = r; | |
545 | ||
546 | return i; | |
547 | } | |
548 | ||
549 | /* | |
550 | * NAME: tp_attach() | |
551 | * | |
552 | * CALLED FROM: | |
553 | * tp_usrreq, PRU_ATTACH | |
554 | * | |
555 | * FUNCTION and ARGUMENTS: | |
556 | * given a socket (so) and a protocol family (dom), allocate a tpcb | |
557 | * and ref structure, initialize everything in the structures that | |
558 | * needs to be initialized. | |
559 | * | |
560 | * RETURN VALUE: | |
561 | * 0 ok | |
562 | * EINVAL if DEBUG(X) in is on and a disaster has occurred | |
563 | * ENOPROTOOPT if TP hasn't been configured or if the | |
564 | * socket wasn't created with tp as its protocol | |
565 | * EISCONN if this socket is already part of a connection | |
566 | * ETOOMANYREFS if ran out of tp reference numbers. | |
567 | * E* whatever error is returned from soreserve() | |
568 | * for from the network-layer pcb allocation routine | |
569 | * | |
570 | * SIDE EFFECTS: | |
571 | * | |
572 | * NOTES: | |
573 | */ | |
a50e2bc0 | 574 | tp_attach(so, dom) |
c32c2ec1 KS |
575 | struct socket *so; |
576 | int dom; | |
577 | { | |
578 | register struct tp_pcb *tpcb; | |
c32c2ec1 KS |
579 | int error; |
580 | int protocol = so->so_proto->pr_protocol; | |
581 | extern struct tp_conn_param tp_conn_param[]; | |
582 | ||
583 | IFDEBUG(D_CONN) | |
584 | printf("tp_attach:dom 0x%x so 0x%x ", dom, so); | |
585 | ENDDEBUG | |
586 | IFTRACE(D_CONN) | |
587 | tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0); | |
588 | ENDTRACE | |
589 | if ( ! tp_param.tpp_configed ) { | |
590 | error = ENOPROTOOPT; /* protocol not available */ | |
591 | goto bad2; | |
592 | } | |
593 | ||
594 | if (so->so_pcb != NULL) { | |
595 | return EISCONN; /* socket already part of a connection*/ | |
596 | } | |
597 | ||
598 | error = soreserve(so, TP_SOCKBUFSIZE, TP_SOCKBUFSIZE); | |
599 | /* later an ioctl will allow reallocation IF still in closed state */ | |
600 | ||
601 | if (error) | |
602 | goto bad2; | |
603 | ||
a50e2bc0 KS |
604 | MALLOC(tpcb, struct tp_pcb *, sizeof(*tpcb), M_PCB, M_NOWAIT); |
605 | if (tpcb == NULL) { | |
c32c2ec1 KS |
606 | error = ENOBUFS; |
607 | goto bad2; | |
608 | } | |
c32c2ec1 KS |
609 | bzero( (caddr_t)tpcb, sizeof (struct tp_pcb) ); |
610 | ||
c32c2ec1 KS |
611 | if ( ((tpcb->tp_lref = tp_getref(tpcb)) & TP_ENOREF) != 0 ) { |
612 | error = ETOOMANYREFS; | |
613 | goto bad3; | |
614 | } | |
615 | tpcb->tp_sock = so; | |
616 | tpcb->tp_domain = dom; | |
617 | if (protocol<ISOPROTO_TP4) { | |
618 | tpcb->tp_netservice = ISO_CONS; | |
619 | tpcb->tp_snduna = (SeqNum) -1;/* kludge so the pseudo-ack from the CR/CC | |
620 | * will generate correct fake-ack values | |
621 | */ | |
622 | } else { | |
623 | tpcb->tp_netservice = (dom== AF_INET)?IN_CLNS:ISO_CLNS; | |
624 | /* the default */ | |
625 | } | |
626 | tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice]; | |
627 | ||
628 | tpcb->tp_cong_win = 1; | |
629 | tpcb->tp_state = TP_CLOSED; | |
630 | tpcb->tp_vers = TP_VERSION; | |
631 | ||
632 | /* Spec says default is 128 octets, | |
633 | * that is, if the tpdusize argument never appears, use 128. | |
634 | * As the initiator, we will always "propose" the 2048 | |
635 | * size, that is, we will put this argument in the CR | |
636 | * always, but accept what the other side sends on the CC. | |
637 | * If the initiator sends us something larger on a CR, | |
638 | * we'll respond w/ this. | |
639 | * Our maximum is 4096. See tp_chksum.c comments. | |
640 | */ | |
641 | tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize; | |
642 | ||
643 | tpcb->tp_seqmask = TP_NML_FMT_MASK; | |
644 | tpcb->tp_seqbit = TP_NML_FMT_BIT; | |
645 | tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1; | |
646 | tpcb->tp_sndhiwat = (SeqNum) - 1; /* a kludge but it works */ | |
647 | tpcb->tp_s_subseq = 0; | |
648 | ||
649 | /* attach to a network-layer protoswitch */ | |
650 | /* new way */ | |
651 | tpcb->tp_nlproto = & nl_protosw[tpcb->tp_netservice]; | |
652 | ASSERT( tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain); | |
653 | #ifdef notdef | |
654 | /* OLD WAY */ | |
655 | /* TODO: properly, this search would be on the basis of | |
656 | * domain,netservice or just netservice only (if you have | |
657 | * IN_CLNS, ISO_CLNS, and ISO_CONS) | |
658 | */ | |
659 | tpcb->tp_nlproto = nl_protosw; | |
660 | while(tpcb->tp_nlproto->nlp_afamily != tpcb->tp_domain ) { | |
661 | if( tpcb->tp_nlproto->nlp_afamily == 0 ) { | |
662 | error = EAFNOSUPPORT; | |
663 | goto bad4; | |
664 | } | |
665 | tpcb->tp_nlproto ++; | |
666 | } | |
667 | #endif notdef | |
668 | ||
669 | /* xx_pcballoc sets so_pcb */ | |
670 | if ( error = (tpcb->tp_nlproto->nlp_pcballoc) ( | |
671 | so, tpcb->tp_nlproto->nlp_pcblist ) ) { | |
672 | goto bad4; | |
673 | } | |
674 | ||
675 | if( dom == AF_INET ) | |
676 | sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb; | |
677 | /* nothing to do for iso case */ | |
678 | ||
679 | tpcb->tp_npcb = (caddr_t) so->so_pcb; | |
680 | so->so_tpcb = (caddr_t) tpcb; | |
681 | ||
682 | return 0; | |
683 | ||
684 | bad4: | |
685 | IFDEBUG(D_CONN) | |
686 | printf("BAD4 in tp_attach, so 0x%x\n", so); | |
687 | ENDDEBUG | |
688 | tp_freeref(tpcb->tp_refp); | |
689 | ||
690 | bad3: | |
691 | IFDEBUG(D_CONN) | |
692 | printf("BAD3 in tp_attach, so 0x%x\n", so); | |
693 | ENDDEBUG | |
694 | ||
a50e2bc0 | 695 | free((caddr_t)tpcb, M_PCB); /* never a cluster */ |
c32c2ec1 KS |
696 | |
697 | bad2: | |
698 | IFDEBUG(D_CONN) | |
699 | printf("BAD2 in tp_attach, so 0x%x\n", so); | |
700 | ENDDEBUG | |
701 | so->so_pcb = 0; | |
702 | so->so_tpcb = 0; | |
703 | sofree(so); | |
704 | ||
a50e2bc0 | 705 | /*bad:*/ |
c32c2ec1 KS |
706 | IFDEBUG(D_CONN) |
707 | printf("BAD in tp_attach, so 0x%x\n", so); | |
708 | ENDDEBUG | |
709 | return error; | |
710 | } | |
711 | ||
712 | /* | |
713 | * NAME: tp_detach() | |
714 | * | |
715 | * CALLED FROM: | |
716 | * tp.trans, on behalf of a user close request | |
717 | * and when the reference timer goes off | |
718 | * (if the disconnect was initiated by the protocol entity | |
719 | * rather than by the user) | |
720 | * | |
721 | * FUNCTION and ARGUMENTS: | |
722 | * remove the tpcb structure from the list of active or | |
723 | * partially active connections, recycle all the mbufs | |
724 | * associated with the pcb, ref structure, sockbufs, etc. | |
725 | * Only free the ref structure if you know that a ref timer | |
726 | * wasn't set for this tpcb. | |
727 | * | |
728 | * RETURNS: Nada | |
729 | * | |
730 | * SIDE EFFECTS: | |
731 | * | |
732 | * NOTES: | |
733 | * tp_soisdisconnected() was already when this is called | |
734 | */ | |
735 | void | |
736 | tp_detach(tpcb) | |
737 | register struct tp_pcb *tpcb; | |
738 | { | |
739 | void tp_freeref(); | |
740 | register struct socket *so = tpcb->tp_sock; | |
741 | ||
742 | IFDEBUG(D_CONN) | |
a50e2bc0 KS |
743 | printf("tp_detach(tpcb 0x%x, so 0x%x)\n", |
744 | tpcb,so); | |
c32c2ec1 KS |
745 | ENDDEBUG |
746 | IFTRACE(D_CONN) | |
747 | tptraceTPCB(TPPTmisc, "tp_detach tpcb so lsufx", | |
7b25382f | 748 | tpcb, so, *(u_short *)(tpcb->tp_lsuffix), 0); |
c32c2ec1 KS |
749 | ENDTRACE |
750 | ||
751 | if (so->so_head) { | |
752 | if (!soqremque(so, 0) && !soqremque(so, 1)) | |
753 | panic("sofree dq"); | |
754 | so->so_head = 0; | |
755 | } | |
756 | ||
757 | IFDEBUG(D_CONN) | |
758 | printf("tp_detach(freeing RTC list snduna 0x%x rcvnxt 0x%x)\n", | |
759 | tpcb->tp_snduna_rtc, | |
760 | tpcb->tp_rcvnxt_rtc); | |
761 | ENDDEBUG | |
762 | ||
763 | #define FREE_RTC_LIST(XXX)\ | |
764 | { register struct tp_rtc *xxr = XXX, *xxs; while (xxr) {\ | |
765 | xxs = xxr->tprt_next;\ | |
766 | m_freem( xxr->tprt_data );\ | |
767 | m_free( dtom(xxr) ); xxr = xxs; }\ | |
768 | XXX = (struct tp_rtc *)0;\ | |
769 | } | |
770 | ||
771 | FREE_RTC_LIST( tpcb->tp_snduna_rtc ); | |
772 | tpcb->tp_sndhiwat_rtc = (struct tp_rtc *)0; | |
773 | ||
774 | FREE_RTC_LIST( tpcb->tp_rcvnxt_rtc ); | |
775 | ||
776 | #undef FREE_RTC_LIST | |
777 | ||
778 | IFDEBUG(D_CONN) | |
779 | printf("calling (...nlproto->...)(0x%x, so 0x%x)\n", | |
780 | so->so_pcb, so); | |
781 | printf("so 0x%x so_head 0x%x, qlen %d q0len %d qlimit %d\n", | |
782 | so, so->so_head, | |
783 | so->so_q0len, so->so_qlen, so->so_qlimit); | |
784 | ENDDEBUG | |
785 | ||
a50e2bc0 | 786 | if ( tpcb->tp_flags & (TPF_DISC_DATA_OUT | TPF_CONN_DATA_OUT ) ) { |
c32c2ec1 KS |
787 | ASSERT( so->so_snd.sb_cc != 0 ); |
788 | IFDEBUG(D_CONN) | |
789 | printf( | |
790 | "detach, flags 0x%x doing sbdrop on so_snd, mb 0x%x cc 0x%x\n", | |
791 | tpcb->tp_flags, so->so_snd.sb_mb, so->so_snd.sb_cc); | |
792 | dump_mbuf( so->so_snd.sb_mb, "detach so snd: \n"); | |
793 | ENDDEBUG | |
794 | if ( so->so_snd.sb_cc != 0 ) | |
a50e2bc0 | 795 | sbflush(&so->so_snd); |
c32c2ec1 KS |
796 | tpcb->tp_flags &= ~(TPF_CONN_DATA_OUT | TPF_DISC_DATA_OUT); |
797 | } | |
798 | if ( tpcb->tp_flags & (TPF_DISC_DATA_IN | TPF_CONN_DATA_IN ) ) { | |
799 | ASSERT( tpcb->tp_Xrcv.sb_cc != 0 ); | |
800 | IFDEBUG(D_CONN) | |
801 | printf( | |
802 | "detach, flags 0x%x doing sbdrop on tp_Xrcv, mb 0x%x cc 0x%x\n", | |
803 | tpcb->tp_flags, tpcb->tp_Xrcv.sb_mb, tpcb->tp_Xrcv.sb_cc); | |
804 | dump_mbuf( tpcb->tp_Xrcv.sb_mb, "detach Xrcv: \n"); | |
805 | ENDDEBUG | |
806 | if( tpcb->tp_Xrcv.sb_cc != 0 ) | |
a50e2bc0 | 807 | sbdrop(&tpcb->tp_Xrcv, (int)tpcb->tp_Xrcv.sb_cc); |
c32c2ec1 KS |
808 | tpcb->tp_flags &= ~(TPF_CONN_DATA_IN | TPF_DISC_DATA_IN); |
809 | } | |
810 | ||
811 | IFDEBUG(D_CONN) | |
812 | printf("so_snd at 0x%x so_rcv at 0x%x\n", &so->so_snd, &so->so_rcv); | |
813 | dump_mbuf(so->so_snd.sb_mb, "so_snd at detach "); | |
814 | printf("about to call LL detach, nlproto 0x%x, nl_detach 0x%x\n", | |
815 | tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach); | |
816 | ENDDEBUG | |
817 | ||
c32c2ec1 | 818 | |
a50e2bc0 KS |
819 | |
820 | (tpcb->tp_nlproto->nlp_pcbdetach)((struct inpcb *)so->so_pcb); | |
821 | /* does an sofree(so) */ | |
822 | ||
c32c2ec1 KS |
823 | IFDEBUG(D_CONN) |
824 | printf("after xxx_pcbdetach\n"); | |
825 | ENDDEBUG | |
826 | ||
827 | if( tpcb->tp_refp->tpr_state == REF_OPENING ) { | |
828 | /* no connection existed here so no reference timer will be called */ | |
829 | IFDEBUG(D_CONN) | |
830 | printf("SETTING ref %d, 0x%x to REF_FREE\n", tpcb->tp_lref, | |
831 | tpcb->tp_refp - &tp_ref[0]); | |
832 | ENDDEBUG | |
833 | ||
834 | tp_freeref(tpcb->tp_refp); | |
835 | } | |
836 | ||
a50e2bc0 KS |
837 | if (tpcb->tp_Xsnd.sb_mb) { |
838 | printf("Unsent Xdata on detach; would panic"); | |
839 | sbflush(&tpcb->tp_Xsnd); | |
840 | } | |
c32c2ec1 KS |
841 | so->so_tpcb = (caddr_t)0; |
842 | ||
843 | /* | |
844 | * Get rid of the cluster mbuf allocated for performance measurements, if | |
845 | * there is one. Note that tpcb->tp_perf_on says nothing about whether or | |
846 | * not a cluster mbuf was allocated, so you have to check for a pointer | |
847 | * to one (that is, we need the TP_PERF_MEASs around the following section | |
848 | * of code, not the IFPERFs) | |
849 | */ | |
850 | #ifdef TP_PERF_MEAS | |
a50e2bc0 KS |
851 | if(tpcb->tp_p_mbuf) { |
852 | register struct mbuf *m = tpcb->tp_p_mbuf; | |
853 | struct mbuf *n; | |
c32c2ec1 KS |
854 | IFDEBUG(D_PERF_MEAS) |
855 | printf("freeing tp_p_meas 0x%x ", tpcb->tp_p_meas); | |
c32c2ec1 | 856 | ENDDEBUG |
a50e2bc0 KS |
857 | do { |
858 | MFREE(m, n); | |
859 | m = n; | |
860 | } while (n); | |
861 | tpcb->tp_p_meas = 0; | |
862 | tpcb->tp_p_mbuf = 0; | |
c32c2ec1 KS |
863 | } |
864 | #endif TP_PERF_MEAS | |
865 | ||
866 | IFDEBUG(D_CONN) | |
a50e2bc0 | 867 | printf( "end of detach, NOT single, tpcb 0x%x\n", tpcb); |
c32c2ec1 | 868 | ENDDEBUG |
a50e2bc0 | 869 | /* free((caddr_t)tpcb, M_PCB); WHere to put this ? */ |
c32c2ec1 | 870 | } |