📄 pk_input.c
字号:
/* * Copyright (c) University of British Columbia, 1984 * Copyright (C) Computer Science Department IV, * University of Erlangen-Nuremberg, Germany, 1992 * Copyright (c) 1991, 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by the * Laboratory for Computation Vision and the Computer Science Department * of the the University of British Columbia and the Computer Science * Department (IV) of the University of Erlangen-Nuremberg, Germany. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)pk_input.c 8.1 (Berkeley) 6/10/93 */#include <sys/param.h>#include <sys/systm.h>#include <sys/mbuf.h>#include <sys/socket.h>#include <sys/protosw.h>#include <sys/socketvar.h>#include <sys/errno.h>#include <net/if.h>#include <net/if_dl.h>#include <net/if_llc.h>#include <net/route.h>#include <netccitt/dll.h>#include <netccitt/x25.h>#include <netccitt/pk.h>#include <netccitt/pk_var.h>#include <netccitt/llc_var.h>struct pkcb_q pkcb_q = {&pkcb_q, &pkcb_q};/* * ccittintr() is the generic interrupt handler for HDLC, LLC2, and X.25. This * allows to have kernel running X.25 but no HDLC or LLC2 or both (in case we * employ boards that do all the stuff themselves, e.g. ADAX X.25 or TPS ISDN.) */voidccittintr (){ extern struct ifqueue pkintrq; extern struct ifqueue hdintrq; extern struct ifqueue llcintrq;#ifdef HDLC if (hdintrq.ifq_len) hdintr ();#endif#ifdef LLC if (llcintrq.ifq_len) llcintr ();#endif if (pkintrq.ifq_len) pkintr ();}struct pkcb *pk_newlink (ia, llnext)struct x25_ifaddr *ia;caddr_t llnext;{ register struct x25config *xcp = &ia -> ia_xc; register struct pkcb *pkp; register struct pklcd *lcp; register struct protosw *pp; unsigned size; pp = pffindproto (AF_CCITT, (int) xcp -> xc_lproto, 0); if (pp == 0 || pp -> pr_output == 0) { pk_message (0, xcp, "link level protosw error"); return ((struct pkcb *)0); } /* * Allocate a network control block structure */ size = sizeof (struct pkcb); pkp = (struct pkcb *) malloc (size, M_PCB, M_WAITOK); if (pkp == 0) return ((struct pkcb *)0); bzero ((caddr_t) pkp, size); pkp -> pk_lloutput = pp -> pr_output; pkp -> pk_llctlinput = (caddr_t (*)()) pp -> pr_ctlinput; pkp -> pk_xcp = xcp; pkp -> pk_ia = ia; pkp -> pk_state = DTE_WAITING; pkp -> pk_llnext = llnext; insque (pkp, &pkcb_q); /* * set defaults */ if (xcp -> xc_pwsize == 0) xcp -> xc_pwsize = DEFAULT_WINDOW_SIZE; if (xcp -> xc_psize == 0) xcp -> xc_psize = X25_PS128; /* * Allocate logical channel descriptor vector */ (void) pk_resize (pkp); return (pkp);}pk_dellink (pkp)register struct pkcb *pkp;{ register int i; register struct protosw *pp; /* * Essentially we have the choice to * (a) go ahead and let the route be deleted and * leave the pkcb associated with that route * as it is, i.e. the connections stay open * (b) do a pk_disconnect() on all channels associated * with the route via the pkcb and then proceed. * * For the time being we stick with (b) */ for (i = 1; i < pkp -> pk_maxlcn; ++i) if (pkp -> pk_chan[i]) pk_disconnect (pkp -> pk_chan[i]); /* * Free the pkcb */ /* * First find the protoswitch to get hold of the link level * protocol to be notified that the packet level entity is * dissolving ... */ pp = pffindproto (AF_CCITT, (int) pkp -> pk_xcp -> xc_lproto, 0); if (pp == 0 || pp -> pr_output == 0) { pk_message (0, pkp -> pk_xcp, "link level protosw error"); return (EPROTONOSUPPORT); } pkp -> pk_refcount--; if (!pkp -> pk_refcount) { struct dll_ctlinfo ctlinfo; remque (pkp); if (pkp -> pk_rt -> rt_llinfo == (caddr_t) pkp) pkp -> pk_rt -> rt_llinfo = (caddr_t) NULL; /* * Tell the link level that the pkcb is dissolving */ if (pp -> pr_ctlinput && pkp -> pk_llnext) { ctlinfo.dlcti_pcb = pkp -> pk_llnext; ctlinfo.dlcti_rt = pkp -> pk_rt; (pp -> pr_ctlinput)(PRC_DISCONNECT_REQUEST, pkp -> pk_xcp, &ctlinfo); } free ((caddr_t) pkp -> pk_chan, M_IFADDR); free ((caddr_t) pkp, M_PCB); } return (0);}pk_resize (pkp)register struct pkcb *pkp;{ struct pklcd *dev_lcp = 0; struct x25config *xcp = pkp -> pk_xcp; if (pkp -> pk_chan && (pkp -> pk_maxlcn != xcp -> xc_maxlcn)) { pk_restart (pkp, X25_RESTART_NETWORK_CONGESTION); dev_lcp = pkp -> pk_chan[0]; free ((caddr_t) pkp -> pk_chan, M_IFADDR); pkp -> pk_chan = 0; } if (pkp -> pk_chan == 0) { unsigned size; pkp -> pk_maxlcn = xcp -> xc_maxlcn; size = (pkp -> pk_maxlcn + 1) * sizeof (struct pklcd *); pkp -> pk_chan = (struct pklcd **) malloc (size, M_IFADDR, M_WAITOK); if (pkp -> pk_chan) { bzero ((caddr_t) pkp -> pk_chan, size); /* * Allocate a logical channel descriptor for lcn 0 */ if (dev_lcp == 0 && (dev_lcp = pk_attach ((struct socket *)0)) == 0) return (ENOBUFS); dev_lcp -> lcd_state = READY; dev_lcp -> lcd_pkp = pkp; pkp -> pk_chan[0] = dev_lcp; } else { if (dev_lcp) pk_close (dev_lcp); return (ENOBUFS); } } return 0;}/* * This procedure is called by the link level whenever the link * becomes operational, is reset, or when the link goes down. *//*VARARGS*/caddr_tpk_ctlinput (code, src, addr) struct sockaddr *src; caddr_t addr;{ register struct pkcb *pkp = (struct pkcb *) addr; switch (code) { case PRC_LINKUP: if (pkp -> pk_state == DTE_WAITING) pk_restart (pkp, X25_RESTART_NETWORK_CONGESTION); break; case PRC_LINKDOWN: pk_restart (pkp, -1); /* Clear all active circuits */ pkp -> pk_state = DTE_WAITING; break; case PRC_LINKRESET: pk_restart (pkp, X25_RESTART_NETWORK_CONGESTION); break; case PRC_CONNECT_INDICATION: { struct rtentry *llrt; if ((llrt = rtalloc1(src, 0)) == 0) return 0; else llrt -> rt_refcnt--; pkp = (((struct npaidbentry *) llrt -> rt_llinfo) -> np_rt) ? (struct pkcb *)(((struct npaidbentry *) llrt -> rt_llinfo) -> np_rt -> rt_llinfo) : (struct pkcb *) 0; if (pkp == (struct pkcb *) 0) return 0; pkp -> pk_llnext = addr; return ((caddr_t) pkp); } case PRC_DISCONNECT_INDICATION: pk_restart (pkp, -1) ; /* Clear all active circuits */ pkp -> pk_state = DTE_WAITING; pkp -> pk_llnext = (caddr_t) 0; } return (0);}struct ifqueue pkintrq;/* * This routine is called if there are semi-smart devices that do HDLC * in hardware and want to queue the packet and call level 3 directly */pkintr (){ register struct mbuf *m; register struct ifaddr *ifa; register struct ifnet *ifp; register int s; for (;;) { s = splimp (); IF_DEQUEUE (&pkintrq, m); splx (s); if (m == 0) break; if (m -> m_len < PKHEADERLN) { printf ("pkintr: packet too short (len=%d)\n", m -> m_len); m_freem (m); continue; } pk_input (m); }}struct mbuf *pk_bad_packet;struct mbuf_cache pk_input_cache = {0 };/* * X.25 PACKET INPUT * * This procedure is called by a link level procedure whenever * an information frame is received. It decodes the packet and * demultiplexes based on the logical channel number. * * We change the original conventions of the UBC code here -- * since there may be multiple pkcb's for a given interface * of type 802.2 class 2, we retrieve which one it is from * m_pkthdr.rcvif (which has been overwritten by lower layers); * That field is then restored for the benefit of upper layers which * may make use of it, such as CLNP. * */#define RESTART_DTE_ORIGINATED(xp) (((xp) -> packet_cause == X25_RESTART_DTE_ORIGINATED) || \ ((xp) -> packet_cause >= X25_RESTART_DTE_ORIGINATED2))pk_input (m)register struct mbuf *m;{ register struct x25_packet *xp; register struct pklcd *lcp; register struct socket *so = 0; register struct pkcb *pkp; int ptype, lcn, lcdstate = LISTEN; if (pk_input_cache.mbc_size || pk_input_cache.mbc_oldsize) mbuf_cache (&pk_input_cache, m); if ((m -> m_flags & M_PKTHDR) == 0) panic ("pkintr"); if ((pkp = (struct pkcb *) m -> m_pkthdr.rcvif) == 0) return; xp = mtod (m, struct x25_packet *); ptype = pk_decode (xp); lcn = LCN(xp); lcp = pkp -> pk_chan[lcn]; /* * If the DTE is in Restart state, then it will ignore data, * interrupt, call setup and clearing, flow control and reset * packets. */ if (lcn < 0 || lcn > pkp -> pk_maxlcn) { pk_message (lcn, pkp -> pk_xcp, "illegal lcn"); m_freem (m); return; } pk_trace (pkp -> pk_xcp, m, "P-In"); if (pkp -> pk_state != DTE_READY && ptype != RESTART && ptype != RESTART_CONF) { m_freem (m); return; } if (lcp) { so = lcp -> lcd_so; lcdstate = lcp -> lcd_state; } else { if (ptype == CLEAR) { /* idle line probe (Datapac specific) */ /* send response on lcd 0's output queue */ lcp = pkp -> pk_chan[0]; lcp -> lcd_template = pk_template (lcn, X25_CLEAR_CONFIRM); pk_output (lcp); m_freem (m); return; } if (ptype != CALL) ptype = INVALID_PACKET; } if (lcn == 0 && ptype != RESTART && ptype != RESTART_CONF) { pk_message (0, pkp -> pk_xcp, "illegal ptype (%d, %s) on lcn 0", ptype, pk_name[ptype / MAXSTATES]); if (pk_bad_packet) m_freem (pk_bad_packet); pk_bad_packet = m; return; } m -> m_pkthdr.rcvif = pkp -> pk_ia -> ia_ifp; switch (ptype + lcdstate) { /* * Incoming Call packet received. */ case CALL + LISTEN: pk_incoming_call (pkp, m); break; /* * Call collision: Just throw this "incoming call" away since * the DCE will ignore it anyway. */ case CALL + SENT_CALL: pk_message ((int) lcn, pkp -> pk_xcp, "incoming call collision"); break; /* * Call confirmation packet received. This usually means our * previous connect request is now complete. */ case CALL_ACCEPTED + SENT_CALL: MCHTYPE(m, MT_CONTROL); pk_call_accepted (lcp, m); break; /* * This condition can only happen if the previous state was * SENT_CALL. Just ignore the packet, eventually a clear * confirmation should arrive. */ case CALL_ACCEPTED + SENT_CLEAR: break; /* * Clear packet received. This requires a complete tear down * of the virtual circuit. Free buffers and control blocks. * and send a clear confirmation. */ case CLEAR + READY: case CLEAR + RECEIVED_CALL: case CLEAR + SENT_CALL: case CLEAR + DATA_TRANSFER: lcp -> lcd_state = RECEIVED_CLEAR; lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CLEAR_CONFIRM); pk_output (lcp); pk_clearcause (pkp, xp); if (lcp -> lcd_upper) { MCHTYPE(m, MT_CONTROL); lcp -> lcd_upper (lcp, m); } pk_close (lcp); lcp = 0; break; /* * Clear collision: Treat this clear packet as a confirmation. */ case CLEAR + SENT_CLEAR: pk_close (lcp); break; /* * Clear confirmation received. This usually means the virtual * circuit is now completely removed. */ case CLEAR_CONF + SENT_CLEAR: pk_close (lcp); break; /* * A clear confirmation on an unassigned logical channel - just * ignore it. Note: All other packets on an unassigned channel * results in a clear. */ case CLEAR_CONF + READY: case CLEAR_CONF + LISTEN: break; /* * Data packet received. Pass on to next level. Move the Q and M * bits into the data portion for the next level. */ case DATA + DATA_TRANSFER: if (lcp -> lcd_reset_condition) { ptype = DELETE_PACKET; break; } /* * Process the P(S) flow control information in this Data packet. * Check that the packets arrive in the correct sequence and that * they are within the "lcd_input_window". Input window rotation is * initiated by the receive interface. */ if (PS(xp) != ((lcp -> lcd_rsn + 1) % MODULUS) || PS(xp) == ((lcp -> lcd_input_window + lcp -> lcd_windowsize) % MODULUS)) { m_freem (m); pk_procerror (RESET, lcp, "p(s) flow control error", 1); break; } lcp -> lcd_rsn = PS(xp); if (pk_ack (lcp, PR(xp)) != PACKET_OK) { m_freem (m); break; } m -> m_data += PKHEADERLN; m -> m_len -= PKHEADERLN; m -> m_pkthdr.len -= PKHEADERLN; lcp -> lcd_rxcnt++; if (lcp -> lcd_flags & X25_MBS_HOLD) { register struct mbuf *n = lcp -> lcd_cps; int mbit = MBIT(xp); octet q_and_d_bits; if (n) { n -> m_pkthdr.len += m -> m_pkthdr.len; while (n -> m_next) n = n -> m_next; n -> m_next = m; m = lcp -> lcd_cps; if (lcp -> lcd_cpsmax && n -> m_pkthdr.len > lcp -> lcd_cpsmax) { pk_procerror (RESET, lcp, "C.P.S. overflow", 128); return; } q_and_d_bits = 0xc0 & *(octet *) xp; xp = (struct x25_packet *) (mtod (m, octet *) - PKHEADERLN); *(octet *) xp |= q_and_d_bits; } if (mbit) { lcp -> lcd_cps = m; pk_flowcontrol (lcp, 0, 1); return; } lcp -> lcd_cps = 0; } if (so == 0) break; if (lcp -> lcd_flags & X25_MQBIT) { octet t = (X25GBITS(xp -> bits, q_bit)) ? t = 0x80 : 0; if (MBIT(xp)) t |= 0x40; m -> m_data -= 1; m -> m_len += 1; m -> m_pkthdr.len += 1; *mtod (m, octet *) = t; } /* * Discard Q-BIT packets if the application * doesn't want to be informed of M and Q bit status */ if (X25GBITS(xp -> bits, q_bit) && (lcp -> lcd_flags & X25_MQBIT) == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -