xref: /csrg-svn/sys/netccitt/hd_output.c (revision 63216)
141703Ssklower /*
241703Ssklower  * Copyright (c) University of British Columbia, 1984
3*63216Sbostic  * Copyright (c) 1990, 1993
4*63216Sbostic  *	The Regents of the University of California.  All rights reserved.
541703Ssklower  *
641703Ssklower  * This code is derived from software contributed to Berkeley by
741703Ssklower  * the Laboratory for Computation Vision and the Computer Science Department
841703Ssklower  * of the University of British Columbia.
941703Ssklower  *
1041703Ssklower  * %sccs.include.redist.c%
1141703Ssklower  *
12*63216Sbostic  *	@(#)hd_output.c	8.1 (Berkeley) 06/10/93
1341703Ssklower  */
1441587Ssklower 
1556530Sbostic #include <sys/param.h>
1656530Sbostic #include <sys/systm.h>
1756530Sbostic #include <sys/mbuf.h>
1856530Sbostic #include <sys/domain.h>
1956530Sbostic #include <sys/socket.h>
2056530Sbostic #include <sys/syslog.h>
2156530Sbostic #include <sys/protosw.h>
2256530Sbostic #include <sys/errno.h>
2356530Sbostic #include <sys/time.h>
2456530Sbostic #include <sys/kernel.h>
2545165Ssklower 
2656530Sbostic #include <net/if.h>
2741587Ssklower 
2856530Sbostic #include <netccitt/hdlc.h>
2956530Sbostic #include <netccitt/hd_var.h>
3056530Sbostic #include <netccitt/x25.h>
3141587Ssklower 
3241587Ssklower /*
3341587Ssklower  *      HDLC OUTPUT INTERFACE
3441587Ssklower  *
3541587Ssklower  *      This routine is called when the X.25 packet layer output routine
3641587Ssklower  *      has a information frame (iframe)  to write.   It is  also called
3741587Ssklower  *      by the input and control routines of the HDLC layer.
3841587Ssklower  */
3941587Ssklower 
hd_output(hdp,m0)4045296Ssklower hd_output (hdp, m0)
4145296Ssklower register struct hdcb *hdp;
4245296Ssklower struct mbuf *m0;
4341587Ssklower {
4443361Ssklower 	struct x25config *xcp;
4545296Ssklower 	register struct mbuf *m = m0;
4645296Ssklower 	int len;
4741587Ssklower 
4841587Ssklower 	if (m == NULL)
4941587Ssklower 		panic ("hd_output");
5052433Ssklower 	if ((m->m_flags & M_PKTHDR) == 0)
5145296Ssklower 		panic ("hd_output 2");
5241587Ssklower 
5341587Ssklower 	if (hdp->hd_state != ABM) {
5441587Ssklower 		m_freem (m);
5541587Ssklower 		return;
5641587Ssklower 	}
5741587Ssklower 
5841587Ssklower 	/*
5941587Ssklower 	 * Make room for the hdlc header either by prepending
6041587Ssklower 	 * another mbuf, or by adjusting the offset and length
6141587Ssklower 	 * of the first mbuf in the mbuf chain.
6241587Ssklower 	 */
6341587Ssklower 
6445296Ssklower 	M_PREPEND(m, HDHEADERLN, M_DONTWAIT);
6543361Ssklower 	if (m == NULL)
6643361Ssklower 		return;
6745296Ssklower 	for (len = 0; m; m = m->m_next)
6845296Ssklower 		len += m->m_len;
6945296Ssklower 	m = m0;
7045296Ssklower 	m->m_pkthdr.len = len;
7141587Ssklower 
7241587Ssklower 	hd_append (&hdp->hd_txq, m);
7341587Ssklower 	hd_start (hdp);
7441587Ssklower }
7541587Ssklower 
hd_start(hdp)7641587Ssklower hd_start (hdp)
7741587Ssklower register struct hdcb *hdp;
7841587Ssklower {
7941587Ssklower 	register struct mbuf *m;
8041587Ssklower 
8141587Ssklower 	/*
8241587Ssklower 	 * The iframe is only transmitted if all these conditions are FALSE.
8341587Ssklower 	 * The iframe remains queued (hdp->hd_txq) however and will be
8441587Ssklower 	 * transmitted as soon as these conditions are cleared.
8541587Ssklower 	 */
8641587Ssklower 
8741587Ssklower 	while (!(hdp->hd_condition & (TIMER_RECOVERY_CONDITION | REMOTE_RNR_CONDITION | REJ_CONDITION))) {
8841587Ssklower 		if (hdp->hd_vs == (hdp->hd_lastrxnr + hdp->hd_xcp->xc_lwsize) % MODULUS) {
8941587Ssklower 
9041587Ssklower 			/* We have now exceeded the  maximum  number  of
9141587Ssklower 			   outstanding iframes. Therefore,  we must wait
9241587Ssklower 			   until  at least  one is acknowledged if this
9341587Ssklower 			   condition  is not  turned off before we are
9441587Ssklower 			   requested to write another iframe. */
9541587Ssklower 			hdp->hd_window_condition++;
9641587Ssklower 			break;
9741587Ssklower 		}
9841587Ssklower 
9941587Ssklower 		/* hd_remove top iframe from transmit queue. */
10041587Ssklower 		if ((m = hd_remove (&hdp->hd_txq)) == NULL)
10141587Ssklower 			break;
10241587Ssklower 
10341587Ssklower 		hd_send_iframe (hdp, m, POLLOFF);
10441587Ssklower 	}
10541587Ssklower }
10641587Ssklower 
10741587Ssklower /*
10841587Ssklower  *  This procedure is passed a buffer descriptor for an iframe. It builds
10941587Ssklower  *  the rest of the control part of the frame and then writes it out.  It
11041587Ssklower  *  also  starts the  acknowledgement  timer and keeps  the iframe in the
11141587Ssklower  *  Retransmit queue (Retxq) just in case  we have to do this again.
11241587Ssklower  *
11341587Ssklower  *  Note: This routine is also called from hd_input.c when retransmission
11441587Ssklower  *       of old frames is required.
11541587Ssklower  */
11641587Ssklower 
hd_send_iframe(hdp,buf,poll_bit)11741587Ssklower hd_send_iframe (hdp, buf, poll_bit)
11841587Ssklower register struct hdcb *hdp;
11941587Ssklower register struct mbuf *buf;
12041587Ssklower int poll_bit;
12141587Ssklower {
12241587Ssklower 	register struct Hdlc_iframe *iframe;
12341587Ssklower 	struct mbuf *m;
12441587Ssklower 
12541587Ssklower 	KILL_TIMER (hdp);
12641587Ssklower 
12741587Ssklower 	if (buf == 0) {
12841587Ssklower 		printf ("hd_send_iframe: zero arg\n");
12941587Ssklower #ifdef HDLCDEBUG
13041587Ssklower 		hd_status (hdp);
13141587Ssklower 		hd_dumptrace (hdp);
13241587Ssklower #endif
13341587Ssklower 		hdp->hd_vs = (hdp->hd_vs + 7) % MODULUS;
13441587Ssklower 		return;
13541587Ssklower 	}
13641587Ssklower 	iframe = mtod (buf, struct Hdlc_iframe *);
13741587Ssklower 
13841587Ssklower 	iframe -> hdlc_0 = 0;
13941587Ssklower 	iframe -> nr = hdp->hd_vr;
14041587Ssklower 	iframe -> pf = poll_bit;
14141587Ssklower 	iframe -> ns = hdp->hd_vs;
14241587Ssklower 	iframe -> address = ADDRESS_B;
14341587Ssklower 	hdp->hd_lasttxnr = hdp->hd_vr;
14441587Ssklower 	hdp->hd_rrtimer = 0;
14541587Ssklower 
14641587Ssklower 	if (hdp->hd_vs == hdp->hd_retxqi) {
14741587Ssklower 		/* Check for retransmissions. */
14841587Ssklower 		/* Put iframe only once in the Retransmission queue. */
14941587Ssklower 		hdp->hd_retxq[hdp->hd_retxqi] = buf;
15041587Ssklower 		hdp->hd_retxqi = (hdp->hd_retxqi + 1) % MODULUS;
15141587Ssklower 		hdp->hd_iframes_out++;
15241587Ssklower 	}
15341587Ssklower 
15441587Ssklower 	hdp->hd_vs = (hdp->hd_vs + 1) % MODULUS;
15541587Ssklower 
15641587Ssklower 	hd_trace (hdp, TX, (struct Hdlc_frame *)iframe);
15741587Ssklower 
15841587Ssklower 	/* Write buffer on device. */
15941587Ssklower 	m = hdp->hd_dontcopy ? buf : m_copy(buf, 0, (int)M_COPYALL);
16041587Ssklower 	if (m == 0) {
16141587Ssklower 		printf("hdlc: out of mbufs\n");
16241587Ssklower 		return;
16341587Ssklower 	}
16443361Ssklower 	(*hdp->hd_output)(hdp, m);
16541587Ssklower 	SET_TIMER (hdp);
16641587Ssklower }
16741587Ssklower 
hd_ifoutput(hdp,m)16843361Ssklower hd_ifoutput(hdp, m)
16945296Ssklower register struct mbuf *m;
17043361Ssklower register struct hdcb *hdp;
17143361Ssklower {
17243361Ssklower 	/*
17343361Ssklower 	 * Queue message on interface, and start output if interface
17443361Ssklower 	 * not yet active.
17543361Ssklower 	 */
17645165Ssklower 	register struct ifnet *ifp = hdp->hd_ifp;
17743361Ssklower 	int s = splimp();
17845296Ssklower 
17943361Ssklower 	if (IF_QFULL(&ifp->if_snd)) {
18043361Ssklower 		IF_DROP(&ifp->if_snd);
18145296Ssklower 	    /* printf("%s%d: HDLC says OK to send but queue full, may hang\n",
18245296Ssklower 			ifp->if_name, ifp->if_unit);*/
18343361Ssklower 		m_freem(m);
18443361Ssklower 	} else {
18543361Ssklower 		IF_ENQUEUE(&ifp->if_snd, m);
18643361Ssklower 		if ((ifp->if_flags & IFF_OACTIVE) == 0)
18743361Ssklower 			(*ifp->if_start)(ifp);
18843361Ssklower 	}
18943361Ssklower 	splx(s);
19043361Ssklower }
19143361Ssklower 
19243361Ssklower 
19341587Ssklower /*
19441587Ssklower  *  This routine gets control when the timer expires because we have not
19541587Ssklower  *  received an acknowledgement for a iframe.
19641587Ssklower  */
19741587Ssklower 
hd_resend_iframe(hdp)19841587Ssklower hd_resend_iframe (hdp)
19941587Ssklower register struct hdcb *hdp;
20041587Ssklower {
20141587Ssklower 
20241587Ssklower 	if (hdp->hd_retxcnt++ < hd_n2) {
20341587Ssklower 		if (!(hdp->hd_condition & TIMER_RECOVERY_CONDITION)) {
20441587Ssklower 			hdp->hd_xx = hdp->hd_vs;
20541587Ssklower 			hdp->hd_condition |= TIMER_RECOVERY_CONDITION;
20641587Ssklower 		}
20741587Ssklower 
20841587Ssklower 		hdp->hd_vs = hdp->hd_lastrxnr;
20941587Ssklower 		hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], POLLON);
21041587Ssklower 	} else {
21141587Ssklower 		/* At this point we have not received a RR even after N2
21241587Ssklower 		   retries - attempt to reset link. */
21341587Ssklower 
21441587Ssklower 		hd_initvars (hdp);
21541587Ssklower 		hd_writeinternal (hdp, SABM, POLLOFF);
21641587Ssklower 		hdp->hd_state = WAIT_UA;
21741587Ssklower 		SET_TIMER (hdp);
21841587Ssklower 		hd_message (hdp, "Timer recovery failed: link down");
21949927Ssklower 		(void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp);
22041587Ssklower 	}
22141587Ssklower }
222