FreeBSD/Linux Kernel Cross Reference
sys/netiso/tp_pcb.c
1 /* $NetBSD: tp_pcb.c,v 1.24 2003/08/07 16:33:40 agc 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.24 2003/08/07 16:33:40 agc 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 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()
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(so)
368 struct socket *so;
369 {
370 soisdisconnecting(so);
371 so->so_state &= ~SS_CANTSENDMORE;
372 #ifdef TP_PERF_MEAS
373 if (DOPERF(sototpcb(so))) {
374 struct tp_pcb *tpcb = sototpcb(so);
375 u_int fsufx, lsufx;
376
377 bcopy((caddr_t) tpcb->tp_fsuffix, (caddr_t) &fsufx,
378 sizeof(u_int));
379 bcopy((caddr_t) tpcb->tp_lsuffix, (caddr_t) &lsufx,
380 sizeof(u_int));
381
382 tpmeas(tpcb->tp_lref, TPtime_close, &time, fsufx, lsufx,
383 tpcb->tp_fref);
384 tpcb->tp_perf_on = 0; /* turn perf off */
385 }
386 #endif
387 }
388
389
390 /*
391 * NAME: tp_soisdisconnected()
392 *
393 * CALLED FROM:
394 * tp.trans
395 *
396 * FUNCTION and ARGUMENTS:
397 * Set state of the socket (so) to reflect that fact that we're disconnectED
398 * Set the state of the reference structure to closed, and
399 * recycle the suffix.
400 * Start a reference timer.
401 *
402 * RETURNS: Nada
403 *
404 * SIDE EFFECTS:
405 *
406 * NOTES:
407 * This differs from the regular soisdisconnected() in that the latter
408 * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags.
409 * We don't want to set those flags because those flags will cause
410 * a SIGPIPE to be delivered in sosend() and we don't like that.
411 * If anyone else is sleeping on this socket, wake 'em up.
412 */
413 void
414 tp_soisdisconnected(tpcb)
415 struct tp_pcb *tpcb;
416 {
417 struct socket *so = tpcb->tp_sock;
418
419 soisdisconnecting(so);
420 so->so_state &= ~SS_CANTSENDMORE;
421 #ifdef TP_PERF_MEAS
422 if (DOPERF(tpcb)) {
423 struct tp_pcb *ttpcb = sototpcb(so);
424 u_int fsufx, lsufx;
425
426 /* CHOKE */
427 bcopy((caddr_t) ttpcb->tp_fsuffix, (caddr_t) &fsufx,
428 sizeof(u_int));
429 bcopy((caddr_t) ttpcb->tp_lsuffix, (caddr_t) &lsufx,
430 sizeof(u_int));
431
432 tpmeas(ttpcb->tp_lref, TPtime_close,
433 &time, &lsufx, &fsufx, ttpcb->tp_fref);
434 tpcb->tp_perf_on = 0; /* turn perf off */
435 }
436 #endif
437
438 tpcb->tp_refstate = REF_FROZEN;
439 tp_recycle_tsuffix(tpcb);
440 tp_etimeout(tpcb, TM_reference, (int) tpcb->tp_refer_ticks);
441 }
442
443 /*
444 * NAME: tp_freeref()
445 *
446 * CALLED FROM:
447 * tp.trans when the reference timer goes off, and
448 * from tp_attach() and tp_detach() when a tpcb is partially set up but not
449 * set up enough to have a ref timer set for it, and it's discarded
450 * due to some sort of error or an early close()
451 *
452 * FUNCTION and ARGUMENTS:
453 * Frees the reference represented by (r) for re-use.
454 *
455 * RETURNS: Nothing
456 *
457 * SIDE EFFECTS:
458 *
459 * NOTES: better be called at clock priority !!!!!
460 */
461 void
462 tp_freeref(n)
463 RefNum n;
464 {
465 struct tp_ref *r = tp_ref + n;
466 struct tp_pcb *tpcb;
467
468 tpcb = r->tpr_pcb;
469 #ifdef ARGO_DEBUG
470 if (argo_debug[D_TIMER]) {
471 printf("tp_freeref called for ref %d pcb %p maxrefopen %d\n",
472 n, tpcb, tp_refinfo.tpr_maxopen);
473 }
474 #endif
475 #ifdef TPPT
476 if (tp_traceflags[D_TIMER]) {
477 tptrace(TPPTmisc, "tp_freeref ref maxrefopen pcb",
478 n, tp_refinfo.tpr_maxopen, tpcb, 0);
479 }
480 #endif
481 if (tpcb == 0)
482 return;
483 #ifdef ARGO_DEBUG
484 if (argo_debug[D_CONN]) {
485 printf("tp_freeref: CLEARING tpr_pcb %p\n", tpcb);
486 }
487 #endif
488 r->tpr_pcb = (struct tp_pcb *) 0;
489 tpcb->tp_refstate = REF_FREE;
490
491 for (r = tp_ref + tp_refinfo.tpr_maxopen; r > tp_ref; r--)
492 if (r->tpr_pcb)
493 break;
494 tp_refinfo.tpr_maxopen = r - tp_ref;
495 tp_refinfo.tpr_numopen--;
496
497 #ifdef ARGO_DEBUG
498 if (argo_debug[D_TIMER]) {
499 printf("tp_freeref ends w/ maxrefopen %d\n", tp_refinfo.tpr_maxopen);
500 }
501 #endif
502 }
503
504 /*
505 * NAME: tp_getref()
506 *
507 * CALLED FROM:
508 * tp_attach()
509 *
510 * FUNCTION and ARGUMENTS:
511 * obtains the next free reference and allocates the appropriate
512 * ref structure, links that structure to (tpcb)
513 *
514 * RETURN VALUE:
515 * a reference number
516 * or TP_ENOREF
517 *
518 * SIDE EFFECTS:
519 *
520 * NOTES:
521 */
522 u_long
523 tp_getref(tpcb)
524 struct tp_pcb *tpcb;
525 {
526 struct tp_ref *r, *rlim;
527 int i;
528 caddr_t obase;
529 unsigned size;
530
531 if (++tp_refinfo.tpr_numopen < tp_refinfo.tpr_size)
532 for (r = tp_refinfo.tpr_base, rlim = r + tp_refinfo.tpr_size;
533 ++r < rlim;) /* tp_ref[0] is never used */
534 if (r->tpr_pcb == 0)
535 goto got_one;
536 /* else have to allocate more space */
537
538 obase = (caddr_t) tp_refinfo.tpr_base;
539 size = tp_refinfo.tpr_size * sizeof(struct tp_ref);
540 r = (struct tp_ref *) malloc(size + size, M_PCB, M_NOWAIT);
541 if (r == 0)
542 return (--tp_refinfo.tpr_numopen, TP_ENOREF);
543 tp_refinfo.tpr_base = tp_ref = r;
544 tp_refinfo.tpr_size *= 2;
545 bcopy(obase, (caddr_t) r, size);
546 free(obase, M_PCB);
547 r = (struct tp_ref *) (size + (caddr_t) r);
548 bzero((caddr_t) r, size);
549
550 got_one:
551 r->tpr_pcb = tpcb;
552 tpcb->tp_refstate = REF_OPENING;
553 i = r - tp_refinfo.tpr_base;
554 if (tp_refinfo.tpr_maxopen < i)
555 tp_refinfo.tpr_maxopen = i;
556 return (u_long) i;
557 }
558
559 /*
560 * NAME: tp_set_npcb()
561 *
562 * CALLED FROM:
563 * tp_attach(), tp_route_to()
564 *
565 * FUNCTION and ARGUMENTS:
566 * given a tpcb, allocate an appropriate lower-lever npcb, freeing
567 * any old ones that might need re-assigning.
568 */
569 int
570 tp_set_npcb(tpcb)
571 struct tp_pcb *tpcb;
572 {
573 struct socket *so = tpcb->tp_sock;
574 int error;
575
576 if (tpcb->tp_nlproto && tpcb->tp_npcb) {
577 short so_state = so->so_state;
578 so->so_state &= ~SS_NOFDREF;
579 (*tpcb->tp_nlproto->nlp_pcbdetach)(tpcb->tp_npcb);
580 so->so_state = so_state;
581 }
582 tpcb->tp_nlproto = &nl_protosw[tpcb->tp_netservice];
583 /* xx_pcballoc sets so_pcb */
584 error = (*tpcb->tp_nlproto->nlp_pcballoc)(so,
585 tpcb->tp_nlproto->nlp_pcblist);
586 tpcb->tp_npcb = so->so_pcb;
587 so->so_pcb = tpcb;
588 return (error);
589 }
590 /*
591 * NAME: tp_attach()
592 *
593 * CALLED FROM:
594 * tp_usrreq, PRU_ATTACH
595 *
596 * FUNCTION and ARGUMENTS:
597 * given a socket (so) and a protocol family (dom), allocate a tpcb
598 * and ref structure, initialize everything in the structures that
599 * needs to be initialized.
600 *
601 * RETURN VALUE:
602 * 0 ok
603 * EINVAL if DEBUG(X) in is on and a disaster has occurred
604 * ENOPROTOOPT if TP hasn't been configured or if the
605 * socket wasn't created with tp as its protocol
606 * EISCONN if this socket is already part of a connection
607 * ETOOMANYREFS if ran out of tp reference numbers.
608 * E* whatever error is returned from soreserve()
609 * for from the network-layer pcb allocation routine
610 *
611 * SIDE EFFECTS:
612 *
613 * NOTES:
614 */
615 int
616 tp_attach(so, protocol)
617 struct socket *so;
618 long protocol;
619 {
620 struct tp_pcb *tpcb;
621 int error = 0;
622 int dom = so->so_proto->pr_domain->dom_family;
623 u_long lref;
624 extern struct tp_conn_param tp_conn_param[];
625
626 #ifdef ARGO_DEBUG
627 if (argo_debug[D_CONN]) {
628 printf("tp_attach:dom 0x%x so %p ", dom, so);
629 }
630 #endif
631 #ifdef TPPT
632 if (tp_traceflags[D_CONN]) {
633 tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0);
634 }
635 #endif
636
637 if (so->so_pcb != NULL) {
638 return EISCONN; /* socket already part of a connection */
639 }
640 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0)
641 error = soreserve(so, tp_sendspace, tp_recvspace);
642 /* later an ioctl will allow reallocation IF still in closed state */
643
644 if (error)
645 goto bad2;
646
647 MALLOC(tpcb, struct tp_pcb *, sizeof(*tpcb), M_PCB, M_NOWAIT);
648 if (tpcb == NULL) {
649 error = ENOBUFS;
650 goto bad2;
651 }
652 bzero((caddr_t) tpcb, sizeof(struct tp_pcb));
653
654 if (((lref = tp_getref(tpcb)) & TP_ENOREF) != 0) {
655 error = ETOOMANYREFS;
656 goto bad3;
657 }
658 tpcb->tp_lref = lref;
659 tpcb->tp_sock = so;
660 tpcb->tp_domain = dom;
661 tpcb->tp_rhiwat = so->so_rcv.sb_hiwat;
662 /* tpcb->tp_proto = protocol; someday maybe? */
663 if (protocol && protocol < ISOPROTO_TP4) {
664 tpcb->tp_netservice = ISO_CONS;
665 tpcb->tp_snduna = (SeqNum) - 1; /* kludge so the pseudo-ack
666 * from the CR/CC will
667 * generate correct fake-ack
668 * values */
669 } else {
670 tpcb->tp_netservice = (dom == AF_INET) ? IN_CLNS : ISO_CLNS;
671 /* the default */
672 }
673 tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice];
674
675 tpcb->tp_state = TP_CLOSED;
676 tpcb->tp_vers = TP_VERSION;
677 tpcb->tp_notdetached = 1;
678
679 /*
680 * Spec says default is 128 octets, that is, if the tpdusize argument
681 * never appears, use 128. As the initiator, we will always "propose"
682 * the 2048 size, that is, we will put this argument in the CR
683 * always, but accept what the other side sends on the CC. If the
684 * initiator sends us something larger on a CR, we'll respond w/
685 * this. Our maximum is 4096. See tp_chksum.c comments.
686 */
687 tpcb->tp_cong_win =
688 tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize;
689
690 tpcb->tp_seqmask = TP_NML_FMT_MASK;
691 tpcb->tp_seqbit = TP_NML_FMT_BIT;
692 tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1;
693
694 /* attach to a network-layer protoswitch */
695 if ((error = tp_set_npcb(tpcb)) != 0)
696 goto bad4;
697 ASSERT(tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain);
698
699 /* nothing to do for iso case */
700 if (dom == AF_INET)
701 sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb;
702
703 return 0;
704
705 bad4:
706 #ifdef ARGO_DEBUG
707 if (argo_debug[D_CONN]) {
708 printf("BAD4 in tp_attach, so %p\n", so);
709 }
710 #endif
711 tp_freeref(tpcb->tp_lref);
712
713 bad3:
714 #ifdef ARGO_DEBUG
715 if (argo_debug[D_CONN]) {
716 printf("BAD3 in tp_attach, so %p\n", so);
717 }
718 #endif
719
720 free((caddr_t) tpcb, M_PCB); /* never a cluster */
721
722 bad2:
723 #ifdef ARGO_DEBUG
724 if (argo_debug[D_CONN]) {
725 printf("BAD2 in tp_attach, so %p\n", so);
726 }
727 #endif
728 so->so_pcb = 0;
729
730 /* bad: */
731 #ifdef ARGO_DEBUG
732 if (argo_debug[D_CONN]) {
733 printf("BAD in tp_attach, so %p\n", so);
734 }
735 #endif
736 return error;
737 }
738
739 /*
740 * NAME: tp_detach()
741 *
742 * CALLED FROM:
743 * tp.trans, on behalf of a user close request
744 * and when the reference timer goes off
745 * (if the disconnect was initiated by the protocol entity
746 * rather than by the user)
747 *
748 * FUNCTION and ARGUMENTS:
749 * remove the tpcb structure from the list of active or
750 * partially active connections, recycle all the mbufs
751 * associated with the pcb, ref structure, sockbufs, etc.
752 * Only free the ref structure if you know that a ref timer
753 * wasn't set for this tpcb.
754 *
755 * RETURNS: Nada
756 *
757 * SIDE EFFECTS:
758 *
759 * NOTES:
760 * tp_soisdisconnected() was already when this is called
761 */
762 void
763 tp_detach(tpcb)
764 struct tp_pcb *tpcb;
765 {
766 struct socket *so = tpcb->tp_sock;
767
768 #ifdef ARGO_DEBUG
769 if (argo_debug[D_CONN]) {
770 printf("tp_detach(tpcb %p, so %p)\n",
771 tpcb, so);
772 }
773 #endif
774 #ifdef TPPT
775 if (tp_traceflags[D_CONN]) {
776 tptraceTPCB(TPPTmisc, "tp_detach tpcb so lsufx",
777 tpcb, so, *(u_short *) (tpcb->tp_lsuffix), 0);
778 }
779 #endif
780
781 #ifdef ARGO_DEBUG
782 if (argo_debug[D_CONN]) {
783 printf("so_snd at %p so_rcv at %p\n", &so->so_snd, &so->so_rcv);
784 dump_mbuf(so->so_snd.sb_mb, "so_snd at detach ");
785 printf("about to call LL detach, nlproto %p, nl_detach %p\n",
786 tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach);
787 }
788 #endif
789
790 if (tpcb->tp_Xsnd.sb_mb) {
791 printf("Unsent Xdata on detach; would panic");
792 sbflush(&tpcb->tp_Xsnd);
793 }
794 if (tpcb->tp_ucddata)
795 m_freem(tpcb->tp_ucddata);
796
797 #ifdef ARGO_DEBUG
798 if (argo_debug[D_CONN]) {
799 printf("reassembly info cnt %d rsyq %p\n",
800 tpcb->tp_rsycnt, tpcb->tp_rsyq);
801 }
802 #endif
803 if (tpcb->tp_rsyq)
804 tp_rsyflush(tpcb);
805
806 if (tpcb->tp_next) {
807 remque(tpcb);
808 tpcb->tp_next = tpcb->tp_prev = 0;
809 }
810 tpcb->tp_notdetached = 0;
811
812 #ifdef ARGO_DEBUG
813 if (argo_debug[D_CONN]) {
814 printf("calling (...nlproto->...)(%p, so %p)\n",
815 tpcb->tp_npcb, so);
816 printf("so %p so_head %p, qlen %d q0len %d qlimit %d\n",
817 so, so->so_head,
818 so->so_q0len, so->so_qlen, so->so_qlimit);
819 }
820 #endif
821
822 (*tpcb->tp_nlproto->nlp_pcbdetach)(tpcb->tp_npcb);
823 /* does an so->so_pcb = 0; sofree(so) */
824
825 #ifdef ARGO_DEBUG
826 if (argo_debug[D_CONN]) {
827 printf("after xxx_pcbdetach\n");
828 }
829 #endif
830
831 if (tpcb->tp_state == TP_LISTENING) {
832 struct tp_pcb **tt;
833 for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten))
834 if (*tt == tpcb)
835 break;
836 if (*tt)
837 *tt = tpcb->tp_nextlisten;
838 else
839 printf("tp_detach from listen: should panic\n");
840 }
841 if (tpcb->tp_refstate == REF_OPENING) {
842 /*
843 * no connection existed here so no reference timer will be
844 * called
845 */
846 #ifdef ARGO_DEBUG
847 if (argo_debug[D_CONN]) {
848 printf("SETTING ref %d to REF_FREE\n", tpcb->tp_lref);
849 }
850 #endif
851
852 tp_freeref(tpcb->tp_lref);
853 }
854 #ifdef TP_PERF_MEAS
855 /*
856 * Get rid of the cluster mbuf allocated for performance
857 * measurements, if there is one. Note that tpcb->tp_perf_on says
858 * nothing about whether or not a cluster mbuf was allocated, so you
859 * have to check for a pointer to one (that is, we need the
860 * TP_PERF_MEASs around the following section of code, not the
861 * IFPERFs)
862 */
863 if (tpcb->tp_p_meas) {
864 struct mbuf *m = tpcb->tp_p_mbuf;
865 struct mbuf *n;
866 #ifdef ARGO_DEBUG
867 if (argo_debug[D_PERF_MEAS]) {
868 printf("freeing tp_p_meas 0x%x ", tpcb->tp_p_meas);
869 }
870 #endif
871 free(tpcb->tp_p_meas, M_PCB);
872 tpcb->tp_p_meas = 0;
873 }
874 #endif /* TP_PERF_MEAS */
875
876 #ifdef ARGO_DEBUG
877 if (argo_debug[D_CONN]) {
878 printf("end of detach, NOT single, tpcb %p\n", tpcb);
879 }
880 #endif
881 /* free((caddr_t)tpcb, M_PCB); WHere to put this ? */
882 }
883
884 struct que {
885 struct tp_pcb *next;
886 struct tp_pcb *prev;
887 } tp_bound_pcbs =
888 {
889 (struct tp_pcb *) & tp_bound_pcbs, (struct tp_pcb *) & tp_bound_pcbs
890 };
891
892 u_short tp_unique;
893
894 int
895 tp_tselinuse(tlen, tsel, siso, reuseaddr)
896 int tlen;
897 caddr_t tsel;
898 struct sockaddr_iso *siso;
899 int reuseaddr;
900 {
901 struct tp_pcb *b = tp_bound_pcbs.next, *l = tp_listeners;
902 struct tp_pcb *t;
903
904 for (;;) {
905 if (b != (struct tp_pcb *) & tp_bound_pcbs) {
906 t = b;
907 b = t->tp_next;
908 } else if (l) {
909 t = l;
910 l = t->tp_nextlisten;
911 } else
912 break;
913 if (tlen == t->tp_lsuffixlen && bcmp(tsel, t->tp_lsuffix, tlen) == 0) {
914 if (t->tp_flags & TPF_GENERAL_ADDR) {
915 if (siso == 0 || reuseaddr == 0)
916 return 1;
917 } else if (siso) {
918 if (siso->siso_family == t->tp_domain &&
919 (*t->tp_nlproto->nlp_cmpnetaddr)(t->tp_npcb,
920 (struct sockaddr *) siso, TP_LOCAL))
921 return 1;
922 } else if (reuseaddr == 0)
923 return 1;
924 }
925 }
926 return 0;
927
928 }
929
930
931 int
932 tp_pcbbind(v, nam, p)
933 void *v;
934 struct mbuf *nam;
935 struct proc *p;
936 {
937 struct tp_pcb *tpcb = v;
938 struct sockaddr_iso *siso = 0;
939 int tlen = 0, wrapped = 0;
940 caddr_t tsel = NULL;
941 u_short tutil;
942
943 if (tpcb->tp_state != TP_CLOSED)
944 return (EINVAL);
945 if (nam) {
946 siso = mtod(nam, struct sockaddr_iso *);
947 switch (siso->siso_family) {
948 default:
949 return (EAFNOSUPPORT);
950 #ifdef ISO
951 case AF_ISO:
952 tlen = siso->siso_tlen;
953 tsel = TSEL(siso);
954 if (siso->siso_nlen == 0)
955 siso = 0;
956 break;
957 #endif
958 #ifdef INET
959 case AF_INET:
960 tsel = (caddr_t) & tutil;
961 if ((tutil = satosin(siso)->sin_port) != 0)
962 tlen = 2;
963 if (satosin(siso)->sin_addr.s_addr == 0)
964 siso = 0;
965 #endif
966 }
967 }
968 if (tpcb->tp_lsuffixlen == 0) {
969 if (tlen) {
970 if (tp_tselinuse(tlen, tsel, siso,
971 tpcb->tp_sock->so_options & SO_REUSEADDR))
972 return (EINVAL);
973 } else {
974 for (tsel = (caddr_t) & tutil, tlen = 2;;) {
975 if (tp_unique++ < ISO_PORT_RESERVED ||
976 tp_unique > ISO_PORT_USERRESERVED) {
977 if (wrapped++)
978 return ESRCH;
979 tp_unique = ISO_PORT_RESERVED;
980 }
981 tutil = htons(tp_unique);
982 if (tp_tselinuse(tlen, tsel, siso, 0) == 0)
983 break;
984 }
985 if (siso)
986 switch (siso->siso_family) {
987 #ifdef ISO
988 case AF_ISO:
989 bcopy(tsel, TSEL(siso), tlen);
990 siso->siso_tlen = tlen;
991 break;
992 #endif
993 #ifdef INET
994 case AF_INET:
995 satosin(siso)->sin_port = tutil;
996 #endif
997 }
998 }
999 bcopy(tsel, tpcb->tp_lsuffix, (tpcb->tp_lsuffixlen = tlen));
1000 insque(tpcb, &tp_bound_pcbs);
1001 } else {
1002 if (tlen || siso == 0)
1003 return (EINVAL);
1004 }
1005 if (siso == 0) {
1006 tpcb->tp_flags |= TPF_GENERAL_ADDR;
1007 return (0);
1008 }
1009 return (*tpcb->tp_nlproto->nlp_pcbbind)(tpcb->tp_npcb, nam, p);
1010 }
Cache object: 0dd2d0dc16db0fae0219314e8528bce2
|