📄 tp_pcb.c
字号:
tp_freeref(n)RefNum n;{ register struct tp_ref *r = tp_ref + n; register struct tp_pcb *tpcb; tpcb = r->tpr_pcb; IFDEBUG(D_TIMER) printf("tp_freeref called for ref %d pcb %x maxrefopen %d\n", n, tpcb, tp_refinfo.tpr_maxopen); ENDDEBUG IFTRACE(D_TIMER) tptrace(TPPTmisc, "tp_freeref ref maxrefopen pcb", n, tp_refinfo.tpr_maxopen, tpcb, 0); ENDTRACE if (tpcb == 0) return; IFDEBUG(D_CONN) printf("tp_freeref: CLEARING tpr_pcb 0x%x\n", tpcb); ENDDEBUG r->tpr_pcb = (struct tp_pcb *)0; tpcb->tp_refstate = REF_FREE; for (r = tp_ref + tp_refinfo.tpr_maxopen; r > tp_ref; r--) if (r->tpr_pcb) break; tp_refinfo.tpr_maxopen = r - tp_ref; tp_refinfo.tpr_numopen--; IFDEBUG(D_TIMER) printf("tp_freeref ends w/ maxrefopen %d\n", tp_refinfo.tpr_maxopen); ENDDEBUG}/* * NAME: tp_getref() * * CALLED FROM: * tp_attach() * * FUNCTION and ARGUMENTS: * obtains the next free reference and allocates the appropriate * ref structure, links that structure to (tpcb) * * RETURN VALUE: * a reference number * or TP_ENOREF * * SIDE EFFECTS: * * NOTES: */u_longtp_getref(tpcb) register struct tp_pcb *tpcb;{ register struct tp_ref *r, *rlim; register int i; caddr_t obase; unsigned size; if (++tp_refinfo.tpr_numopen < tp_refinfo.tpr_size) for (r = tp_refinfo.tpr_base, rlim = r + tp_refinfo.tpr_size; ++r < rlim; ) /* tp_ref[0] is never used */ if (r->tpr_pcb == 0) goto got_one; /* else have to allocate more space */ obase = (caddr_t)tp_refinfo.tpr_base; size = tp_refinfo.tpr_size * sizeof(struct tp_ref); r = (struct tp_ref *) malloc(size + size, M_PCB, M_NOWAIT); if (r == 0) return (--tp_refinfo.tpr_numopen, TP_ENOREF); tp_refinfo.tpr_base = tp_ref = r; tp_refinfo.tpr_size *= 2; bcopy(obase, (caddr_t)r, size); free(obase, M_PCB); r = (struct tp_ref *)(size + (caddr_t)r); bzero((caddr_t)r, size);got_one: r->tpr_pcb = tpcb; tpcb->tp_refstate = REF_OPENING; i = r - tp_refinfo.tpr_base; if (tp_refinfo.tpr_maxopen < i) tp_refinfo.tpr_maxopen = i; return (u_long)i;}/* * NAME: tp_set_npcb() * * CALLED FROM: * tp_attach(), tp_route_to() * * FUNCTION and ARGUMENTS: * given a tpcb, allocate an appropriate lower-lever npcb, freeing * any old ones that might need re-assigning. */tp_set_npcb(tpcb)register struct tp_pcb *tpcb;{ register struct socket *so = tpcb->tp_sock; int error; if (tpcb->tp_nlproto && tpcb->tp_npcb) { short so_state = so->so_state; so->so_state &= ~SS_NOFDREF; tpcb->tp_nlproto->nlp_pcbdetach(tpcb->tp_npcb); so->so_state = so_state; } tpcb->tp_nlproto = &nl_protosw[tpcb->tp_netservice]; /* xx_pcballoc sets so_pcb */ error = tpcb->tp_nlproto->nlp_pcballoc(so, tpcb->tp_nlproto->nlp_pcblist); tpcb->tp_npcb = so->so_pcb; so->so_pcb = (caddr_t)tpcb; return (error);}/* * NAME: tp_attach() * * CALLED FROM: * tp_usrreq, PRU_ATTACH * * FUNCTION and ARGUMENTS: * given a socket (so) and a protocol family (dom), allocate a tpcb * and ref structure, initialize everything in the structures that * needs to be initialized. * * RETURN VALUE: * 0 ok * EINVAL if DEBUG(X) in is on and a disaster has occurred * ENOPROTOOPT if TP hasn't been configured or if the * socket wasn't created with tp as its protocol * EISCONN if this socket is already part of a connection * ETOOMANYREFS if ran out of tp reference numbers. * E* whatever error is returned from soreserve() * for from the network-layer pcb allocation routine * * SIDE EFFECTS: * * NOTES: */tp_attach(so, protocol) struct socket *so; int protocol;{ register struct tp_pcb *tpcb; int error = 0; int dom = so->so_proto->pr_domain->dom_family; u_long lref; extern struct tp_conn_param tp_conn_param[]; IFDEBUG(D_CONN) printf("tp_attach:dom 0x%x so 0x%x ", dom, so); ENDDEBUG IFTRACE(D_CONN) tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0); ENDTRACE if (so->so_pcb != NULL) { return EISCONN; /* socket already part of a connection*/ } if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) error = soreserve(so, tp_sendspace, tp_recvspace); /* later an ioctl will allow reallocation IF still in closed state */ if (error) goto bad2; MALLOC(tpcb, struct tp_pcb *, sizeof(*tpcb), M_PCB, M_NOWAIT); if (tpcb == NULL) { error = ENOBUFS; goto bad2; } bzero( (caddr_t)tpcb, sizeof (struct tp_pcb) ); if ( ((lref = tp_getref(tpcb)) & TP_ENOREF) != 0 ) { error = ETOOMANYREFS; goto bad3; } tpcb->tp_lref = lref; tpcb->tp_sock = so; tpcb->tp_domain = dom; tpcb->tp_rhiwat = so->so_rcv.sb_hiwat; /* tpcb->tp_proto = protocol; someday maybe? */ if (protocol && protocol<ISOPROTO_TP4) { tpcb->tp_netservice = ISO_CONS; tpcb->tp_snduna = (SeqNum) -1;/* kludge so the pseudo-ack from the CR/CC * will generate correct fake-ack values */ } else { tpcb->tp_netservice = (dom== AF_INET)?IN_CLNS:ISO_CLNS; /* the default */ } tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice]; tpcb->tp_state = TP_CLOSED; tpcb->tp_vers = TP_VERSION; tpcb->tp_notdetached = 1; /* Spec says default is 128 octets, * that is, if the tpdusize argument never appears, use 128. * As the initiator, we will always "propose" the 2048 * size, that is, we will put this argument in the CR * always, but accept what the other side sends on the CC. * If the initiator sends us something larger on a CR, * we'll respond w/ this. * Our maximum is 4096. See tp_chksum.c comments. */ tpcb->tp_cong_win = tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize; tpcb->tp_seqmask = TP_NML_FMT_MASK; tpcb->tp_seqbit = TP_NML_FMT_BIT; tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1; /* attach to a network-layer protoswitch */ if ( error = tp_set_npcb(tpcb)) goto bad4; ASSERT( tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain); /* nothing to do for iso case */ if( dom == AF_INET ) sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb; return 0;bad4: IFDEBUG(D_CONN) printf("BAD4 in tp_attach, so 0x%x\n", so); ENDDEBUG tp_freeref(tpcb->tp_lref);bad3: IFDEBUG(D_CONN) printf("BAD3 in tp_attach, so 0x%x\n", so); ENDDEBUG free((caddr_t)tpcb, M_PCB); /* never a cluster */bad2: IFDEBUG(D_CONN) printf("BAD2 in tp_attach, so 0x%x\n", so); ENDDEBUG so->so_pcb = 0;/*bad:*/ IFDEBUG(D_CONN) printf("BAD in tp_attach, so 0x%x\n", so); ENDDEBUG return error;}/* * NAME: tp_detach() * * CALLED FROM: * tp.trans, on behalf of a user close request * and when the reference timer goes off * (if the disconnect was initiated by the protocol entity * rather than by the user) * * FUNCTION and ARGUMENTS: * remove the tpcb structure from the list of active or * partially active connections, recycle all the mbufs * associated with the pcb, ref structure, sockbufs, etc. * Only free the ref structure if you know that a ref timer * wasn't set for this tpcb. * * RETURNS: Nada * * SIDE EFFECTS: * * NOTES: * tp_soisdisconnected() was already when this is called */voidtp_detach(tpcb) register struct tp_pcb *tpcb;{ void tp_freeref(), tp_rsyflush(); register struct socket *so = tpcb->tp_sock; IFDEBUG(D_CONN) printf("tp_detach(tpcb 0x%x, so 0x%x)\n", tpcb,so); ENDDEBUG IFTRACE(D_CONN) tptraceTPCB(TPPTmisc, "tp_detach tpcb so lsufx", tpcb, so, *(u_short *)(tpcb->tp_lsuffix), 0); ENDTRACE IFDEBUG(D_CONN) printf("so_snd at 0x%x so_rcv at 0x%x\n", &so->so_snd, &so->so_rcv); dump_mbuf(so->so_snd.sb_mb, "so_snd at detach "); printf("about to call LL detach, nlproto 0x%x, nl_detach 0x%x\n", tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach); ENDDEBUG if (tpcb->tp_Xsnd.sb_mb) { printf("Unsent Xdata on detach; would panic"); sbflush(&tpcb->tp_Xsnd); } if (tpcb->tp_ucddata) m_freem(tpcb->tp_ucddata); IFDEBUG(D_CONN) printf("reassembly info cnt %d rsyq 0x%x\n", tpcb->tp_rsycnt, tpcb->tp_rsyq); ENDDEBUG if (tpcb->tp_rsyq) tp_rsyflush(tpcb); if (tpcb->tp_next) { remque(tpcb); tpcb->tp_next = tpcb->tp_prev = 0; } tpcb->tp_notdetached = 0; IFDEBUG(D_CONN) printf("calling (...nlproto->...)(0x%x, so 0x%x)\n", tpcb->tp_npcb, so); printf("so 0x%x so_head 0x%x, qlen %d q0len %d qlimit %d\n", so, so->so_head, so->so_q0len, so->so_qlen, so->so_qlimit); ENDDEBUG (tpcb->tp_nlproto->nlp_pcbdetach)(tpcb->tp_npcb); /* does an so->so_pcb = 0; sofree(so) */ IFDEBUG(D_CONN) printf("after xxx_pcbdetach\n"); ENDDEBUG if (tpcb->tp_state == TP_LISTENING) { register struct tp_pcb **tt; for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten)) if (*tt == tpcb) break; if (*tt) *tt = tpcb->tp_nextlisten; else printf("tp_detach from listen: should panic\n"); } if (tpcb->tp_refstate == REF_OPENING ) { /* no connection existed here so no reference timer will be called */ IFDEBUG(D_CONN) printf("SETTING ref %d to REF_FREE\n", tpcb->tp_lref); ENDDEBUG tp_freeref(tpcb->tp_lref); }#ifdef TP_PERF_MEAS /* * Get rid of the cluster mbuf allocated for performance measurements, if * there is one. Note that tpcb->tp_perf_on says nothing about whether or * not a cluster mbuf was allocated, so you have to check for a pointer * to one (that is, we need the TP_PERF_MEASs around the following section * of code, not the IFPERFs) */ if (tpcb->tp_p_mbuf) { register struct mbuf *m = tpcb->tp_p_mbuf; struct mbuf *n; IFDEBUG(D_PERF_MEAS) printf("freeing tp_p_meas 0x%x ", tpcb->tp_p_meas); ENDDEBUG do { MFREE(m, n); m = n; } while (n); tpcb->tp_p_meas = 0; tpcb->tp_p_mbuf = 0; }#endif /* TP_PERF_MEAS */ IFDEBUG(D_CONN) printf( "end of detach, NOT single, tpcb 0x%x\n", tpcb); ENDDEBUG /* free((caddr_t)tpcb, M_PCB); WHere to put this ? */}struct que { struct tp_pcb *next; struct tp_pcb *prev;} tp_bound_pcbs ={(struct tp_pcb *)&tp_bound_pcbs, (struct tp_pcb *)&tp_bound_pcbs};u_short tp_unique;tp_tselinuse(tlen, tsel, siso, reuseaddr)caddr_t tsel;register struct sockaddr_iso *siso;{ struct tp_pcb *b = tp_bound_pcbs.next, *l = tp_listeners; register struct tp_pcb *t; for (;;) { if (b != (struct tp_pcb *)&tp_bound_pcbs) { t = b; b = t->tp_next; } else if (l) { t = l; l = t->tp_nextlisten; } else break; if (tlen == t->tp_lsuffixlen && bcmp(tsel, t->tp_lsuffix, tlen) == 0) { if (t->tp_flags & TPF_GENERAL_ADDR) { if (siso == 0 || reuseaddr == 0) return 1; } else if (siso) { if (siso->siso_family == t->tp_domain && t->tp_nlproto->nlp_cmpnetaddr(t->tp_npcb, siso, TP_LOCAL)) return 1; } else if (reuseaddr == 0) return 1; } } return 0;}tp_pcbbind(tpcb, nam)register struct tp_pcb *tpcb;register struct mbuf *nam;{ register struct sockaddr_iso *siso = 0; int tlen = 0, wrapped = 0; caddr_t tsel; u_short tutil; if (tpcb->tp_state != TP_CLOSED) return (EINVAL); if (nam) { siso = mtod(nam, struct sockaddr_iso *); switch (siso->siso_family) { default: return (EAFNOSUPPORT);#ifdef ISO case AF_ISO: tlen = siso->siso_tlen; tsel = TSEL(siso); if (siso->siso_nlen == 0) siso = 0; break;#endif#ifdef INET case AF_INET: tsel = (caddr_t)&tutil; if (tutil = ((struct sockaddr_in *)siso)->sin_port) { tlen = 2; } if (((struct sockaddr_in *)siso)->sin_addr.s_addr == 0) siso = 0; }#endif } if (tpcb->tp_lsuffixlen == 0) { if (tlen) { if (tp_tselinuse(tlen, tsel, siso, tpcb->tp_sock->so_options & SO_REUSEADDR)) return (EINVAL); } else { for (tsel = (caddr_t)&tutil, tlen = 2;;){ if (tp_unique++ < ISO_PORT_RESERVED || tp_unique > ISO_PORT_USERRESERVED) { if (wrapped++) return ESRCH; tp_unique = ISO_PORT_RESERVED; } tutil = htons(tp_unique); if (tp_tselinuse(tlen, tsel, siso, 0) == 0) break; } if (siso) switch (siso->siso_family) {#ifdef ISO case AF_ISO: bcopy(tsel, TSEL(siso), tlen); siso->siso_tlen = tlen; break;#endif#ifdef INET case AF_INET: ((struct sockaddr_in *)siso)->sin_port = tutil;#endif } } bcopy(tsel, tpcb->tp_lsuffix, (tpcb->tp_lsuffixlen = tlen)); insque(tpcb, &tp_bound_pcbs); } else { if (tlen || siso == 0) return (EINVAL); } if (siso == 0) { tpcb->tp_flags |= TPF_GENERAL_ADDR; return (0); } return tpcb->tp_nlproto->nlp_pcbbind(tpcb->tp_npcb, nam);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -