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