📄 pk_subr.c
字号:
pkp -> pk_chan[ni] -> lcd_lcn = ni; } } for (i = 1; i <= pkp -> pk_maxlcn; ++i) if ((lcp = pkp -> pk_chan[i]) != NULL) { /* if (lcp -> lcd_so) soisconnecting (lcp -> lcd_so); */ lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL); pk_callrequest (lcp, lcp -> lcd_ceaddr, pkp -> pk_xcp); (*pkp -> pk_ia -> ia_start) (lcp); }}struct bcdinfo { octet *cp; unsigned posn;};/* * Build the rest of the CALL REQUEST packet. Fill in calling * address, facilities fields and the user data field. */pk_callrequest (lcp, sa, xcp)struct pklcd *lcp;register struct sockaddr_x25 *sa;register struct x25config *xcp;{ register struct x25_calladdr *a; register struct mbuf *m = lcp -> lcd_template; register struct x25_packet *xp = mtod (m, struct x25_packet *); struct bcdinfo b; if (lcp -> lcd_flags & X25_DBIT) X25SBITS(xp -> bits, d_bit, 1); a = (struct x25_calladdr *) &xp -> packet_data; b.cp = (octet *) a -> address_field; b.posn = 0; X25SBITS(a -> addrlens, called_addrlen, to_bcd (&b, sa, xcp)); X25SBITS(a -> addrlens, calling_addrlen, to_bcd (&b, &xcp -> xc_addr, xcp)); if (b.posn & 0x01) *b.cp++ &= 0xf0; m -> m_pkthdr.len = m -> m_len += b.cp - (octet *) a; if (lcp -> lcd_facilities) { m -> m_pkthdr.len += (m -> m_next = lcp -> lcd_facilities) -> m_pkthdr.len; lcp -> lcd_facilities = 0; } else pk_build_facilities (m, sa, (int)xcp -> xc_type); m_copyback (m, m -> m_pkthdr.len, sa -> x25_udlen, sa -> x25_udata);}pk_build_facilities (m, sa, type)register struct mbuf *m;struct sockaddr_x25 *sa;{ register octet *cp; register octet *fcp; register int revcharge; cp = mtod (m, octet *) + m -> m_len; fcp = cp + 1; revcharge = sa -> x25_opts.op_flags & X25_REVERSE_CHARGE ? 1 : 0; /* * This is specific to Datapac X.25(1976) DTEs. International * calls must have the "hi priority" bit on. */ if (type == X25_1976 && sa -> x25_opts.op_psize == X25_PS128) revcharge |= 02; if (revcharge) { *fcp++ = FACILITIES_REVERSE_CHARGE; *fcp++ = revcharge; } switch (type) { case X25_1980: case X25_1984: *fcp++ = FACILITIES_PACKETSIZE; *fcp++ = sa -> x25_opts.op_psize; *fcp++ = sa -> x25_opts.op_psize; *fcp++ = FACILITIES_WINDOWSIZE; *fcp++ = sa -> x25_opts.op_wsize; *fcp++ = sa -> x25_opts.op_wsize; } *cp = fcp - cp - 1; m -> m_pkthdr.len = (m -> m_len += *cp + 1);}to_bcd (b, sa, xcp)register struct bcdinfo *b;struct sockaddr_x25 *sa;register struct x25config *xcp;{ register char *x = sa -> x25_addr; unsigned start = b -> posn; /* * The nodnic and prepnd0 stuff looks tedious, * but it does allow full X.121 addresses to be used, * which is handy for routing info (& OSI type 37 addresses). */ if (xcp -> xc_addr.x25_net && (xcp -> xc_nodnic || xcp -> xc_prepnd0)) { char dnicname[sizeof (long) * NBBY/3 + 2]; register char *p = dnicname; sprintf (p, "%d", xcp -> xc_addr.x25_net & 0x7fff); for (; *p; p++) /* *p == 0 means dnic matched */ if ((*p ^ *x++) & 0x0f) break; if (*p || xcp -> xc_nodnic == 0) x = sa -> x25_addr; if (*p && xcp -> xc_prepnd0) { if ((b -> posn)++ & 0x01) *(b -> cp)++; else *(b -> cp) = 0; } } while (*x) if ((b -> posn)++ & 0x01) *(b -> cp)++ |= *x++ & 0x0F; else *(b -> cp) = *x++ << 4; return ((b -> posn) - start);}/* * This routine gets the first available logical channel number. The * search is * - from the highest number to lowest number if playing DTE, and * - from lowest to highest number if playing DCE. */pk_getlcn (pkp)register struct pkcb *pkp;{ register int i; if (pkp -> pk_chan == 0) return (0); if ( pkp -> pk_dxerole & DTE_PLAYDCE ) { for (i = 1; i <= pkp -> pk_maxlcn; ++i) if (pkp -> pk_chan[i] == NULL) break; } else { for (i = pkp -> pk_maxlcn; i > 0; --i) if (pkp -> pk_chan[i] == NULL) break; } i = ( i > pkp -> pk_maxlcn ? 0 : i ); return (i);}/* * This procedure sends a CLEAR request packet. The lc state is * set to "SENT_CLEAR". */pk_clear (lcp, diagnostic, abortive)register struct pklcd *lcp;{ register struct mbuf *m = pk_template (lcp -> lcd_lcn, X25_CLEAR); m -> m_len += 2; m -> m_pkthdr.len += 2; mtod (m, struct x25_packet *) -> packet_data = 0; mtod (m, octet *)[4] = diagnostic; if (lcp -> lcd_facilities) { m -> m_next = lcp -> lcd_facilities; m -> m_pkthdr.len += m -> m_next -> m_len; lcp -> lcd_facilities = 0; } if (abortive) lcp -> lcd_template = m; else { struct socket *so = lcp -> lcd_so; struct sockbuf *sb = so ? & so -> so_snd : & lcp -> lcd_sb; sbappendrecord (sb, m); } pk_output (lcp);}/* * This procedure generates RNR's or RR's to inhibit or enable * inward data flow, if the current state changes (blocked ==> open or * vice versa), or if forced to generate one. One forces RNR's to ack data. */pk_flowcontrol (lcp, inhibit, forced)register struct pklcd *lcp;{ inhibit = (inhibit != 0); if (lcp == 0 || lcp -> lcd_state != DATA_TRANSFER || (forced == 0 && lcp -> lcd_rxrnr_condition == inhibit)) return; lcp -> lcd_rxrnr_condition = inhibit; lcp -> lcd_template = pk_template (lcp -> lcd_lcn, inhibit ? X25_RNR : X25_RR); pk_output (lcp);}/* * This procedure sends a RESET request packet. It re-intializes * virtual circuit. */staticpk_reset (lcp, diagnostic)register struct pklcd *lcp;{ register struct mbuf *m; register struct socket *so = lcp -> lcd_so; if (lcp -> lcd_state != DATA_TRANSFER) return; if (so) so -> so_error = ECONNRESET; lcp -> lcd_reset_condition = TRUE; /* Reset all the control variables for the channel. */ pk_flush (lcp); lcp -> lcd_window_condition = lcp -> lcd_rnr_condition = lcp -> lcd_intrconf_pending = FALSE; lcp -> lcd_rsn = MODULUS - 1; lcp -> lcd_ssn = 0; lcp -> lcd_output_window = lcp -> lcd_input_window = lcp -> lcd_last_transmitted_pr = 0; m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESET); m -> m_pkthdr.len = m -> m_len += 2; mtod (m, struct x25_packet *) -> packet_data = 0; mtod (m, octet *)[4] = diagnostic; pk_output (lcp);}/* * This procedure frees all data queued for output or delivery on a * virtual circuit. */pk_flush (lcp)register struct pklcd *lcp;{ register struct socket *so; if (lcp -> lcd_template) m_freem (lcp -> lcd_template); if (lcp -> lcd_cps) { m_freem (lcp -> lcd_cps); lcp -> lcd_cps = 0; } if (lcp -> lcd_facilities) { m_freem (lcp -> lcd_facilities); lcp -> lcd_facilities = 0; } if (so = lcp -> lcd_so) sbflush (&so -> so_snd); else sbflush (&lcp -> lcd_sb);}/* * This procedure handles all local protocol procedure errors. */pk_procerror (error, lcp, errstr, diagnostic)register struct pklcd *lcp;char *errstr;{ pk_message (lcp -> lcd_lcn, lcp -> lcd_pkp -> pk_xcp, errstr); switch (error) { case CLEAR: if (lcp -> lcd_so) { lcp -> lcd_so -> so_error = ECONNABORTED; soisdisconnecting (lcp -> lcd_so); } pk_clear (lcp, diagnostic, 1); break; case RESET: pk_reset (lcp, diagnostic); }}/* * This procedure is called during the DATA TRANSFER state to check * and process the P(R) values received in the DATA, RR OR RNR * packets. */pk_ack (lcp, pr)struct pklcd *lcp;unsigned pr;{ register struct socket *so = lcp -> lcd_so; if (lcp -> lcd_output_window == pr) return (PACKET_OK); if (lcp -> lcd_output_window < lcp -> lcd_ssn) { if (pr < lcp -> lcd_output_window || pr > lcp -> lcd_ssn) { pk_procerror (RESET, lcp, "p(r) flow control error", 2); return (ERROR_PACKET); } } else { if (pr < lcp -> lcd_output_window && pr > lcp -> lcd_ssn) { pk_procerror (RESET, lcp, "p(r) flow control error #2", 2); return (ERROR_PACKET); } } lcp -> lcd_output_window = pr; /* Rotate window. */ if (lcp -> lcd_window_condition == TRUE) lcp -> lcd_window_condition = FALSE; if (so && ((so -> so_snd.sb_flags & SB_WAIT) || (so -> so_snd.sb_flags & SB_NOTIFY))) sowwakeup (so); return (PACKET_OK);}/* * This procedure decodes the X.25 level 3 packet returning a * code to be used in switchs or arrays. */pk_decode (xp)register struct x25_packet *xp;{ register int type; if (X25GBITS(xp -> bits, fmt_identifier) != 1) return (INVALID_PACKET);#ifdef ancient_history /* * Make sure that the logical channel group number is 0. * This restriction may be removed at some later date. */ if (xp -> lc_group_number != 0) return (INVALID_PACKET);#endif /* * Test for data packet first. */ if (!(xp -> packet_type & DATA_PACKET_DESIGNATOR)) return (DATA); /* * Test if flow control packet (RR or RNR). */ if (!(xp -> packet_type & RR_OR_RNR_PACKET_DESIGNATOR)) switch (xp -> packet_type & 0x1f) { case X25_RR: return (RR); case X25_RNR: return (RNR); case X25_REJECT: return (REJECT); } /* * Determine the rest of the packet types. */ switch (xp -> packet_type) { case X25_CALL: type = CALL; break; case X25_CALL_ACCEPTED: type = CALL_ACCEPTED; break; case X25_CLEAR: type = CLEAR; break; case X25_CLEAR_CONFIRM: type = CLEAR_CONF; break; case X25_INTERRUPT: type = INTERRUPT; break; case X25_INTERRUPT_CONFIRM: type = INTERRUPT_CONF; break; case X25_RESET: type = RESET; break; case X25_RESET_CONFIRM: type = RESET_CONF; break; case X25_RESTART: type = RESTART; break; case X25_RESTART_CONFIRM: type = RESTART_CONF; break; case X25_DIAGNOSTIC: type = DIAG_TYPE; break; default: type = INVALID_PACKET; } return (type);}/* * A restart packet has been received. Print out the reason * for the restart. */pk_restartcause (pkp, xp)struct pkcb *pkp;register struct x25_packet *xp;{ register struct x25config *xcp = pkp -> pk_xcp; register int lcn = LCN(xp); switch (xp -> packet_data) { case X25_RESTART_LOCAL_PROCEDURE_ERROR: pk_message (lcn, xcp, "restart: local procedure error"); break; case X25_RESTART_NETWORK_CONGESTION: pk_message (lcn, xcp, "restart: network congestion"); break; case X25_RESTART_NETWORK_OPERATIONAL: pk_message (lcn, xcp, "restart: network operational"); break; default: pk_message (lcn, xcp, "restart: unknown cause"); }}#define MAXRESETCAUSE 7int Reset_cause[] = { EXRESET, EXROUT, 0, EXRRPE, 0, EXRLPE, 0, EXRNCG};/* * A reset packet has arrived. Return the cause to the user. */pk_resetcause (pkp, xp)struct pkcb *pkp;register struct x25_packet *xp;{ register struct pklcd *lcp = pkp -> pk_chan[LCN(xp)]; register int code = xp -> packet_data; if (code > MAXRESETCAUSE) code = 7; /* EXRNCG */ pk_message (LCN(xp), lcp -> lcd_pkp, "reset code 0x%x, diagnostic 0x%x", xp -> packet_data, 4[(u_char *)xp]); if (lcp -> lcd_so) lcp -> lcd_so -> so_error = Reset_cause[code];}#define MAXCLEARCAUSE 25int Clear_cause[] = { EXCLEAR, EXCBUSY, 0, EXCINV, 0, EXCNCG, 0, 0, 0, EXCOUT, 0, EXCAB, 0, EXCNOB, 0, 0, 0, EXCRPE, 0, EXCLPE, 0, 0, 0, 0, 0, EXCRRC};/* * A clear packet has arrived. Return the cause to the user. */pk_clearcause (pkp, xp)struct pkcb *pkp;register struct x25_packet *xp;{ register struct pklcd *lcp = pkp -> pk_chan[LCN(xp)]; register int code = xp -> packet_data; if (code > MAXCLEARCAUSE) code = 5; /* EXRNCG */ if (lcp -> lcd_so) lcp -> lcd_so -> so_error = Clear_cause[code];}char *format_ntn (xcp)register struct x25config *xcp;{ return (xcp -> xc_addr.x25_addr);}/* VARARGS1 */pk_message (lcn, xcp, fmt, a1, a2, a3, a4, a5, a6)struct x25config *xcp;char *fmt;{ if (lcn) if (!PQEMPTY) printf ("X.25(%s): lcn %d: ", format_ntn (xcp), lcn); else printf ("X.25: lcn %d: ", lcn); else if (!PQEMPTY) printf ("X.25(%s): ", format_ntn (xcp)); else printf ("X.25: "); printf (fmt, a1, a2, a3, a4, a5, a6); printf ("\n");}pk_fragment (lcp, m0, qbit, mbit, wait)struct mbuf *m0;register struct pklcd *lcp;{ register struct mbuf *m = m0; register struct x25_packet *xp; register struct sockbuf *sb; struct mbuf *head = 0, *next, **mp = &head, *m_split (); int totlen, psize = 1 << (lcp -> lcd_packetsize); if (m == 0) return 0; if (m -> m_flags & M_PKTHDR == 0) panic ("pk_fragment"); totlen = m -> m_pkthdr.len; m -> m_act = 0; sb = lcp -> lcd_so ? &lcp -> lcd_so -> so_snd : & lcp -> lcd_sb; do { if (totlen > psize) { if ((next = m_split (m, psize, wait)) == 0) goto abort; totlen -= psize; } else next = 0; M_PREPEND(m, PKHEADERLN, wait); if (m == 0) goto abort; *mp = m; mp = & m -> m_act; *mp = 0; xp = mtod (m, struct x25_packet *); 0[(char *)xp] = 0; if (qbit) X25SBITS(xp -> bits, q_bit, 1); if (lcp -> lcd_flags & X25_DBIT) X25SBITS(xp -> bits, d_bit, 1); X25SBITS(xp -> bits, fmt_identifier, 1); xp -> packet_type = X25_DATA; SET_LCN(xp, lcp -> lcd_lcn); if (next || (mbit && (totlen == psize || (lcp -> lcd_flags & X25_DBIT)))) SMBIT(xp, 1); } while (m = next); for (m = head; m; m = next) { next = m -> m_act; m -> m_act = 0; sbappendrecord (sb, m); } return 0;abort: if (wait) panic ("pk_fragment null mbuf after wait"); if (next) m_freem (next); for (m = head; m; m = next) { next = m -> m_act; m_freem (m); } return ENOBUFS;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -