]> git.saurik.com Git - apple/xnu.git/blob - bsd/netiso/tp_pcb.c
a4b91724f9a12075fc542b87074552d71a4010ab
[apple/xnu.git] / bsd / netiso / tp_pcb.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*-
23 * Copyright (c) 1991, 1993
24 * The Regents of the University of California. All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 * This product includes software developed by the University of
37 * California, Berkeley and its contributors.
38 * 4. Neither the name of the University nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
53 *
54 * @(#)tp_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 }