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