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