FreeBSD/Linux Kernel Cross Reference
sys/netiso/tp_pcb.c
1 /* $NetBSD: tp_pcb.c,v 1.36 2008/04/23 09:57:59 plunky 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.36 2008/04/23 09:57:59 plunky 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 0,
139 },
140 /* IN_CLNS: TP4 CONNECTION LESS */
141 {
142 TP_NRETRANS, /* short p_Nretrans; */
143 20, /* 10 sec *//* short p_dr_ticks; */
144
145 20, /* 10 sec *//* short p_cc_ticks; */
146 20, /* 10 sec *//* short p_dt_ticks; */
147
148 40, /* 20 sec *//* short p_x_ticks; */
149 80, /* 40 sec *//* short p_cr_ticks; */
150
151 240, /* 2 min *//* short p_keepalive_ticks; */
152 10, /* 5 sec *//* short p_sendack_ticks; */
153
154 600, /* 5 min *//* short p_ref_ticks; */
155 360, /* 3 min *//* short p_inact_ticks; */
156
157 (short) 100, /* short p_lcdtfract */
158 (short) TP_SOCKBUFSIZE, /* short p_winsize */
159 TP_TPDUSIZE, /* u_char p_tpdusize */
160
161 TPACK_WINDOW, /* 4 bits p_ack_strat */
162 TPRX_USE_CW | TPRX_FASTSTART,
163 /* 4 bits p_rx_strat */
164 TP_CLASS_4, /* 5 bits p_class */
165 1, /* 1 bit xtd format */
166 1, /* 1 bit xpd service */
167 1, /* 1 bit use_checksum */
168 0, /* 1 bit use net xpd */
169 0, /* 1 bit use rcc */
170 0, /* 1 bit use efc */
171 1, /* no disc indications */
172 0, /* don't change params */
173 IN_CLNS, /* p_netservice */
174 0,
175 },
176 /* ISO_CONS: TP0 CONNECTION MODE */
177 {
178 TP_NRETRANS, /* short p_Nretrans; */
179 0, /* n/a *//* short p_dr_ticks; */
180
181 40, /* 20 sec *//* short p_cc_ticks; */
182 0, /* n/a *//* short p_dt_ticks; */
183
184 0, /* n/a *//* short p_x_ticks; */
185 360, /* 3 min *//* short p_cr_ticks; */
186
187 0, /* n/a *//* short p_keepalive_ticks; */
188 0, /* n/a *//* short p_sendack_ticks; */
189
190 600, /* for cr/cc to clear *//* short p_ref_ticks; */
191 0, /* n/a *//* short p_inact_ticks; */
192
193 /*
194 * Use tp4 defaults just in case the user changes ONLY the
195 * class
196 */
197 (short) 100, /* short p_lcdtfract */
198 (short) TP0_SOCKBUFSIZE, /* short p_winsize */
199 TP0_TPDUSIZE, /* 8 bits p_tpdusize */
200
201 0, /* 4 bits p_ack_strat */
202 0, /* 4 bits p_rx_strat */
203 TP_CLASS_0, /* 5 bits p_class */
204 0, /* 1 bit xtd format */
205 0, /* 1 bit xpd service */
206 0, /* 1 bit use_checksum */
207 0, /* 1 bit use net xpd */
208 0, /* 1 bit use rcc */
209 0, /* 1 bit use efc */
210 0, /* no disc indications */
211 0, /* don't change params */
212 ISO_CONS, /* p_netservice */
213 0,
214 },
215 /* ISO_COSNS: TP4 CONNECTION LESS SERVICE over CONSNS */
216 {
217 TP_NRETRANS, /* short p_Nretrans; */
218 40, /* 20 sec *//* short p_dr_ticks; */
219
220 40, /* 20 sec *//* short p_cc_ticks; */
221 80, /* 40 sec *//* short p_dt_ticks; */
222
223 120, /* 1 min *//* short p_x_ticks; */
224 360, /* 3 min *//* short p_cr_ticks; */
225
226 360, /* 3 min *//* short p_keepalive_ticks; */
227 20, /* 10 sec *//* short p_sendack_ticks; */
228
229 600, /* 5 min *//* short p_ref_ticks; */
230 480, /* 4 min *//* short p_inact_ticks; */
231
232 (short) 100, /* short p_lcdtfract */
233 (short) TP0_SOCKBUFSIZE, /* short p_winsize */
234 TP0_TPDUSIZE, /* u_char p_tpdusize */
235
236 TPACK_WINDOW, /* 4 bits p_ack_strat */
237 TPRX_USE_CW, /* No fast start */
238 /* 4 bits p_rx_strat */
239 TP_CLASS_4 | TP_CLASS_0, /* 5 bits p_class */
240 0, /* 1 bit xtd format */
241 1, /* 1 bit xpd service */
242 1, /* 1 bit use_checksum */
243 0, /* 1 bit use net xpd */
244 0, /* 1 bit use rcc */
245 0, /* 1 bit use efc */
246 0, /* no disc indications */
247 0, /* don't change params */
248 ISO_COSNS, /* p_netservice */
249 0,
250 },
251 };
252
253 #ifdef INET
254 struct inpcbtable tp_inpcb;
255 #endif /* INET */
256 #ifdef ISO
257 struct isopcb tp_isopcb;
258 #endif /* ISO */
259
260 struct tp_stat tp_stat;
261 u_int tp_start_win;
262
263 struct nl_protosw nl_protosw[] = {
264 /* ISO_CLNS */
265 #ifdef ISO
266 {AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr,
267 iso_putsufx, iso_getsufx,
268 iso_recycle_tsuffix,
269 tpclnp_mtu, iso_pcbbind, iso_pcbconnect,
270 iso_pcbdisconnect, iso_pcbdetach,
271 iso_pcballoc,
272 tpclnp_output, tpclnp_output_dg, iso_nlctloutput,
273 (void *) & tp_isopcb,
274 },
275 #else
276 { .nlp_afamily = 0, },
277 #endif /* ISO */
278 /* IN_CLNS */
279 #ifdef INET
280 {AF_INET, in_putnetaddr, in_getnetaddr, in_cmpnetaddr,
281 in_putsufx, in_getsufx,
282 in_recycle_tsuffix,
283 tpip_mtu, in_pcbbind, in_pcbconnect,
284 in_pcbdisconnect, in_pcbdetach,
285 in_pcballoc,
286 tpip_output, tpip_output_dg, /* nl_ctloutput */ NULL,
287 (void *) & tp_inpcb,
288 },
289 #else
290 { .nlp_afamily = 0, },
291 #endif /* INET */
292 /* ISO_CONS */
293 { .nlp_afamily = 0, },
294 /* End of protosw marker */
295 { .nlp_afamily = 0, },
296 };
297
298 u_long tp_sendspace = 1024 * 4;
299 u_long tp_recvspace = 1024 * 4;
300
301 /*
302 * NAME: tp_init()
303 *
304 * CALLED FROM:
305 * autoconf through the protosw structure
306 *
307 * FUNCTION:
308 * initialize tp machine
309 *
310 * RETURNS: Nada
311 *
312 * SIDE EFFECTS:
313 *
314 * NOTES:
315 */
316 void
317 tp_init(void)
318 {
319 static int init_done = 0;
320
321 if (init_done++)
322 return;
323
324 #ifdef INET
325 /* FOR INET */
326 in_pcbinit(&tp_inpcb, 1, 1);
327 #endif
328 #ifdef ISO
329 /* FOR ISO */
330 tp_isopcb.isop_next = tp_isopcb.isop_prev = &tp_isopcb;
331 #endif
332
333 tp_start_win = 2;
334
335 tp_timerinit();
336 bzero((void *) & tp_stat, sizeof(struct tp_stat));
337 }
338
339 /*
340 * NAME: tp_soisdisconnecting()
341 *
342 * CALLED FROM:
343 * tp.trans
344 *
345 * FUNCTION and ARGUMENTS:
346 * Set state of the socket (so) to reflect that fact that we're disconnectING
347 *
348 * RETURNS: Nada
349 *
350 * SIDE EFFECTS:
351 *
352 * NOTES:
353 * This differs from the regular soisdisconnecting() in that the latter
354 * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags.
355 * We don't want to set those flags because those flags will cause
356 * a SIGPIPE to be delivered in sosend() and we don't like that.
357 * If anyone else is sleeping on this socket, wake 'em up.
358 */
359 void
360 tp_soisdisconnecting(struct socket *so)
361 {
362 soisdisconnecting(so);
363 so->so_state &= ~SS_CANTSENDMORE;
364 #ifdef TP_PERF_MEAS
365 if (DOPERF(sototpcb(so))) {
366 struct tp_pcb *tpcb = sototpcb(so);
367 u_int fsufx, lsufx;
368 struct timeval now;
369
370 bcopy((void *) tpcb->tp_fsuffix, (void *) &fsufx,
371 sizeof(u_int));
372 bcopy((void *) tpcb->tp_lsuffix, (void *) &lsufx,
373 sizeof(u_int));
374
375 getmicrotime(&now);
376 tpmeas(tpcb->tp_lref, TPtime_close, &now, fsufx, lsufx,
377 tpcb->tp_fref);
378 tpcb->tp_perf_on = 0; /* turn perf off */
379 }
380 #endif
381 }
382
383
384 /*
385 * NAME: tp_soisdisconnected()
386 *
387 * CALLED FROM:
388 * tp.trans
389 *
390 * FUNCTION and ARGUMENTS:
391 * Set state of the socket (so) to reflect that fact that we're disconnectED
392 * Set the state of the reference structure to closed, and
393 * recycle the suffix.
394 * Start a reference timer.
395 *
396 * RETURNS: Nada
397 *
398 * SIDE EFFECTS:
399 *
400 * NOTES:
401 * This differs from the regular soisdisconnected() in that the latter
402 * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags.
403 * We don't want to set those flags because those flags will cause
404 * a SIGPIPE to be delivered in sosend() and we don't like that.
405 * If anyone else is sleeping on this socket, wake 'em up.
406 */
407 void
408 tp_soisdisconnected(struct tp_pcb *tpcb)
409 {
410 struct socket *so = tpcb->tp_sock;
411
412 soisdisconnecting(so);
413 so->so_state &= ~SS_CANTSENDMORE;
414 #ifdef TP_PERF_MEAS
415 if (DOPERF(tpcb)) {
416 struct tp_pcb *ttpcb = sototpcb(so);
417 u_int fsufx, lsufx;
418 struct timeval now;
419
420 /* CHOKE */
421 bcopy((void *) ttpcb->tp_fsuffix, (void *) &fsufx,
422 sizeof(u_int));
423 bcopy((void *) ttpcb->tp_lsuffix, (void *) &lsufx,
424 sizeof(u_int));
425
426 getmicrotime(&now);
427 tpmeas(ttpcb->tp_lref, TPtime_close,
428 &now, &lsufx, &fsufx, ttpcb->tp_fref);
429 tpcb->tp_perf_on = 0; /* turn perf off */
430 }
431 #endif
432
433 tpcb->tp_refstate = REF_FROZEN;
434 tp_recycle_tsuffix(tpcb);
435 tp_etimeout(tpcb, TM_reference, (int) tpcb->tp_refer_ticks);
436 }
437
438 /*
439 * NAME: tp_freeref()
440 *
441 * CALLED FROM:
442 * tp.trans when the reference timer goes off, and
443 * from tp_attach() and tp_detach() when a tpcb is partially set up but not
444 * set up enough to have a ref timer set for it, and it's discarded
445 * due to some sort of error or an early close()
446 *
447 * FUNCTION and ARGUMENTS:
448 * Frees the reference represented by (r) for re-use.
449 *
450 * RETURNS: Nothing
451 *
452 * SIDE EFFECTS:
453 *
454 * NOTES: better be called at clock priority !!!!!
455 */
456 void
457 tp_freeref(RefNum n)
458 {
459 struct tp_ref *r = tp_ref + n;
460 struct tp_pcb *tpcb;
461
462 tpcb = r->tpr_pcb;
463 #ifdef ARGO_DEBUG
464 if (argo_debug[D_TIMER]) {
465 printf("tp_freeref called for ref %d pcb %p maxrefopen %d\n",
466 n, tpcb, tp_refinfo.tpr_maxopen);
467 }
468 #endif
469 #ifdef TPPT
470 if (tp_traceflags[D_TIMER]) {
471 tptrace(TPPTmisc, "tp_freeref ref maxrefopen pcb",
472 n, tp_refinfo.tpr_maxopen, tpcb, 0);
473 }
474 #endif
475 if (tpcb == 0)
476 return;
477 #ifdef ARGO_DEBUG
478 if (argo_debug[D_CONN]) {
479 printf("tp_freeref: CLEARING tpr_pcb %p\n", tpcb);
480 }
481 #endif
482 r->tpr_pcb = (struct tp_pcb *) 0;
483 tpcb->tp_refstate = REF_FREE;
484
485 for (r = tp_ref + tp_refinfo.tpr_maxopen; r > tp_ref; r--)
486 if (r->tpr_pcb)
487 break;
488 tp_refinfo.tpr_maxopen = r - tp_ref;
489 tp_refinfo.tpr_numopen--;
490
491 #ifdef ARGO_DEBUG
492 if (argo_debug[D_TIMER]) {
493 printf("tp_freeref ends w/ maxrefopen %d\n", tp_refinfo.tpr_maxopen);
494 }
495 #endif
496 }
497
498 /*
499 * NAME: tp_getref()
500 *
501 * CALLED FROM:
502 * tp_attach()
503 *
504 * FUNCTION and ARGUMENTS:
505 * obtains the next free reference and allocates the appropriate
506 * ref structure, links that structure to (tpcb)
507 *
508 * RETURN VALUE:
509 * a reference number
510 * or TP_ENOREF
511 *
512 * SIDE EFFECTS:
513 *
514 * NOTES:
515 */
516 u_long
517 tp_getref(struct tp_pcb *tpcb)
518 {
519 struct tp_ref *r, *rlim;
520 int i;
521 void * obase;
522 unsigned size;
523
524 if (++tp_refinfo.tpr_numopen < tp_refinfo.tpr_size)
525 for (r = tp_refinfo.tpr_base, rlim = r + tp_refinfo.tpr_size;
526 ++r < rlim;) /* tp_ref[0] is never used */
527 if (r->tpr_pcb == 0)
528 goto got_one;
529 /* else have to allocate more space */
530
531 obase = (void *) tp_refinfo.tpr_base;
532 size = tp_refinfo.tpr_size * sizeof(struct tp_ref);
533 r = (struct tp_ref *) malloc(size + size, M_PCB, M_NOWAIT);
534 if (r == 0)
535 return (--tp_refinfo.tpr_numopen, TP_ENOREF);
536 tp_refinfo.tpr_base = tp_ref = r;
537 tp_refinfo.tpr_size *= 2;
538 memcpy(r, obase, size);
539 free(obase, M_PCB);
540 r = (struct tp_ref *)(size + (char *)r);
541 bzero((void *) r, size);
542
543 got_one:
544 r->tpr_pcb = tpcb;
545 tpcb->tp_refstate = REF_OPENING;
546 i = r - tp_refinfo.tpr_base;
547 if (tp_refinfo.tpr_maxopen < i)
548 tp_refinfo.tpr_maxopen = i;
549 return (u_long) i;
550 }
551
552 /*
553 * NAME: tp_set_npcb()
554 *
555 * CALLED FROM:
556 * tp_attach(), tp_route_to()
557 *
558 * FUNCTION and ARGUMENTS:
559 * given a tpcb, allocate an appropriate lower-lever npcb, freeing
560 * any old ones that might need re-assigning.
561 */
562 int
563 tp_set_npcb(struct tp_pcb *tpcb)
564 {
565 struct socket *so = tpcb->tp_sock;
566 int error;
567
568 if (tpcb->tp_nlproto && tpcb->tp_npcb) {
569 short so_state = so->so_state;
570 so->so_state &= ~SS_NOFDREF;
571 (*tpcb->tp_nlproto->nlp_pcbdetach)(tpcb->tp_npcb);
572 so->so_state = so_state;
573 }
574 tpcb->tp_nlproto = &nl_protosw[tpcb->tp_netservice];
575 /* xx_pcballoc sets so_pcb */
576 error = (*tpcb->tp_nlproto->nlp_pcballoc)(so,
577 tpcb->tp_nlproto->nlp_pcblist);
578 tpcb->tp_npcb = so->so_pcb;
579 so->so_pcb = tpcb;
580 return (error);
581 }
582 /*
583 * NAME: tp_attach()
584 *
585 * CALLED FROM:
586 * tp_usrreq, PRU_ATTACH
587 *
588 * FUNCTION and ARGUMENTS:
589 * given a socket (so) and a protocol family (dom), allocate a tpcb
590 * and ref structure, initialize everything in the structures that
591 * needs to be initialized.
592 *
593 * RETURN VALUE:
594 * 0 ok
595 * EINVAL if DEBUG(X) in is on and a disaster has occurred
596 * ENOPROTOOPT if TP hasn't been configured or if the
597 * socket wasn't created with tp as its protocol
598 * EISCONN if this socket is already part of a connection
599 * ETOOMANYREFS if ran out of tp reference numbers.
600 * E* whatever error is returned from soreserve()
601 * for from the network-layer pcb allocation routine
602 *
603 * SIDE EFFECTS:
604 *
605 * NOTES:
606 */
607 int
608 tp_attach(struct socket *so, int protocol)
609 {
610 struct tp_pcb *tpcb;
611 int error = 0;
612 int dom = so->so_proto->pr_domain->dom_family;
613 u_long lref;
614
615 #ifdef ARGO_DEBUG
616 if (argo_debug[D_CONN]) {
617 printf("tp_attach:dom 0x%x so %p ", dom, so);
618 }
619 #endif
620 #ifdef TPPT
621 if (tp_traceflags[D_CONN]) {
622 tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0);
623 }
624 #endif
625
626 if (so->so_pcb != NULL) {
627 return EISCONN; /* socket already part of a connection */
628 }
629 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0)
630 error = soreserve(so, tp_sendspace, tp_recvspace);
631 /* later an ioctl will allow reallocation IF still in closed state */
632
633 if (error)
634 goto bad2;
635
636 MALLOC(tpcb, struct tp_pcb *, sizeof(*tpcb), M_PCB, M_NOWAIT|M_ZERO);
637 if (tpcb == NULL) {
638 error = ENOBUFS;
639 goto bad2;
640 }
641
642 if (((lref = tp_getref(tpcb)) & TP_ENOREF) != 0) {
643 error = ETOOMANYREFS;
644 goto bad3;
645 }
646 tpcb->tp_lref = lref;
647 tpcb->tp_sock = so;
648 tpcb->tp_domain = dom;
649 tpcb->tp_rhiwat = so->so_rcv.sb_hiwat;
650 /* tpcb->tp_proto = protocol; someday maybe? */
651 if (protocol && protocol < ISOPROTO_TP4) {
652 tpcb->tp_netservice = ISO_CONS;
653 tpcb->tp_snduna = (SeqNum) - 1; /* kludge so the pseudo-ack
654 * from the CR/CC will
655 * generate correct fake-ack
656 * values */
657 } else {
658 tpcb->tp_netservice = (dom == AF_INET) ? IN_CLNS : ISO_CLNS;
659 /* the default */
660 }
661 tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice];
662
663 tpcb->tp_state = TP_CLOSED;
664 tpcb->tp_vers = TP_VERSION;
665 tpcb->tp_notdetached = 1;
666
667 /*
668 * Spec says default is 128 octets, that is, if the tpdusize argument
669 * never appears, use 128. As the initiator, we will always "propose"
670 * the 2048 size, that is, we will put this argument in the CR
671 * always, but accept what the other side sends on the CC. If the
672 * initiator sends us something larger on a CR, we'll respond w/
673 * this. Our maximum is 4096. See tp_chksum.c comments.
674 */
675 tpcb->tp_cong_win =
676 tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize;
677
678 tpcb->tp_seqmask = TP_NML_FMT_MASK;
679 tpcb->tp_seqbit = TP_NML_FMT_BIT;
680 tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1;
681
682 /* attach to a network-layer protoswitch */
683 if ((error = tp_set_npcb(tpcb)) != 0)
684 goto bad4;
685 ASSERT(tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain);
686
687 /* nothing to do for iso case */
688 if (dom == AF_INET) {
689 /* tp_set_npcb sets it */
690 KASSERT(so->so_pcb != NULL);
691 sotoinpcb(so)->inp_ppcb = (void *) tpcb;
692 }
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((void *) 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 iso_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((void *)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, const char *tsel, struct sockaddr_iso *siso,
886 int reuseaddr)
887 {
888 struct tp_pcb *b = tp_bound_pcbs.next, *l = tp_listeners;
889 struct tp_pcb *t;
890
891 for (;;) {
892 if (b != (struct tp_pcb *) & tp_bound_pcbs) {
893 t = b;
894 b = t->tp_next;
895 } else if (l) {
896 t = l;
897 l = t->tp_nextlisten;
898 } else
899 break;
900 if (tlen == t->tp_lsuffixlen && bcmp(tsel, t->tp_lsuffix, tlen) == 0) {
901 if (t->tp_flags & TPF_GENERAL_ADDR) {
902 if (siso == 0 || reuseaddr == 0)
903 return 1;
904 } else if (siso) {
905 if (siso->siso_family == t->tp_domain &&
906 (*t->tp_nlproto->nlp_cmpnetaddr)(t->tp_npcb,
907 (struct sockaddr *) siso, TP_LOCAL))
908 return 1;
909 } else if (reuseaddr == 0)
910 return 1;
911 }
912 }
913 return 0;
914
915 }
916
917
918 int
919 tp_pcbbind(void *v, struct mbuf *nam, struct lwp *l)
920 {
921 struct tp_pcb *tpcb = v;
922 struct sockaddr_iso *siso = 0;
923 int tlen = 0, wrapped = 0;
924 const char *tsel = NULL;
925 u_short tutil;
926
927 if (tpcb->tp_state != TP_CLOSED)
928 return (EINVAL);
929 if (nam) {
930 siso = mtod(nam, struct sockaddr_iso *);
931 switch (siso->siso_family) {
932 default:
933 return (EAFNOSUPPORT);
934 #ifdef ISO
935 case AF_ISO:
936 tlen = siso->siso_tlen;
937 tsel = TSEL(siso);
938 if (siso->siso_nlen == 0)
939 siso = 0;
940 break;
941 #endif
942 #ifdef INET
943 case AF_INET:
944 tsel = (void *) & tutil;
945 if ((tutil = satosin(siso)->sin_port) != 0)
946 tlen = 2;
947 if (satosin(siso)->sin_addr.s_addr == 0)
948 siso = 0;
949 #endif
950 }
951 }
952 if (tpcb->tp_lsuffixlen == 0) {
953 if (tlen) {
954 if (tp_tselinuse(tlen, tsel, siso,
955 tpcb->tp_sock->so_options & SO_REUSEADDR))
956 return (EINVAL);
957 } else {
958 for (tsel = (void *) & tutil, tlen = 2;;) {
959 if (tp_unique++ < ISO_PORT_RESERVED ||
960 tp_unique > ISO_PORT_USERRESERVED) {
961 if (wrapped++)
962 return ESRCH;
963 tp_unique = ISO_PORT_RESERVED;
964 }
965 tutil = htons(tp_unique);
966 if (tp_tselinuse(tlen, tsel, siso, 0) == 0)
967 break;
968 }
969 if (siso)
970 switch (siso->siso_family) {
971 #ifdef ISO
972 case AF_ISO:
973 memcpy(WRITABLE_TSEL(siso), tsel, tlen);
974 siso->siso_tlen = tlen;
975 break;
976 #endif
977 #ifdef INET
978 case AF_INET:
979 satosin(siso)->sin_port = tutil;
980 #endif
981 }
982 }
983 bcopy(tsel, tpcb->tp_lsuffix, (tpcb->tp_lsuffixlen = tlen));
984 iso_insque(tpcb, &tp_bound_pcbs);
985 } else {
986 if (tlen || siso == 0)
987 return (EINVAL);
988 }
989 if (siso == 0) {
990 tpcb->tp_flags |= TPF_GENERAL_ADDR;
991 return (0);
992 }
993 return (*tpcb->tp_nlproto->nlp_pcbbind)(tpcb->tp_npcb, nam, l);
994 }
Cache object: 1a54e0e007bbc2813f04717d4cc71696
|