xref: /csrg-svn/sys/netccitt/hd_output.c (revision 41703)
1*41703Ssklower /*
2*41703Ssklower  * Copyright (c) University of British Columbia, 1984
3*41703Ssklower  * Copyright (c) 1990 The Regents of the University of California.
4*41703Ssklower  * All rights reserved.
5*41703Ssklower  *
6*41703Ssklower  * This code is derived from software contributed to Berkeley by
7*41703Ssklower  * the Laboratory for Computation Vision and the Computer Science Department
8*41703Ssklower  * of the University of British Columbia.
9*41703Ssklower  *
10*41703Ssklower  * %sccs.include.redist.c%
11*41703Ssklower  *
12*41703Ssklower  *	@(#)hd_output.c	7.2 (Berkeley) 05/11/90
13*41703Ssklower  */
1441587Ssklower 
1541587Ssklower #include "../h/param.h"
1641587Ssklower #include "../h/systm.h"
1741587Ssklower #include "../h/mbuf.h"
1841587Ssklower #include "../h/domain.h"
1941587Ssklower #include "../h/socket.h"
2041587Ssklower #include "../h/protosw.h"
2141587Ssklower #include "../h/errno.h"
2241587Ssklower #include "../h/time.h"
2341587Ssklower #include "../h/kernel.h"
2441587Ssklower #include "../net/if.h"
2541587Ssklower 
2641587Ssklower #include "../netccitt/hdlc.h"
2741587Ssklower #include "../netccitt/hd_var.h"
2841587Ssklower #include "../netccitt/x25.h"
2941587Ssklower 
3041587Ssklower /*
3141587Ssklower  *      HDLC OUTPUT INTERFACE
3241587Ssklower  *
3341587Ssklower  *      This routine is called when the X.25 packet layer output routine
3441587Ssklower  *      has a information frame (iframe)  to write.   It is  also called
3541587Ssklower  *      by the input and control routines of the HDLC layer.
3641587Ssklower  */
3741587Ssklower 
3841587Ssklower hd_output (m, xcp)
3941587Ssklower struct x25config *xcp;
4041587Ssklower register struct mbuf *m;
4141587Ssklower {
4241587Ssklower 	register struct hdcb *hdp;
4341587Ssklower 	static struct x25config *lastxcp;
4441587Ssklower 	static struct hdcb *lasthdp;
4541587Ssklower 
4641587Ssklower 	if (m == NULL)
4741587Ssklower 		panic ("hd_output");
4841587Ssklower 
4941587Ssklower 	if (xcp == lastxcp)
5041587Ssklower 		hdp = lasthdp;
5141587Ssklower 	else {
5241587Ssklower 		for (hdp = hdcbhead; ; hdp = hdp->hd_next) {
5341587Ssklower 			if (hdp == 0) {
5441587Ssklower 				printf("hd_output: can't find hdcb for %X\n", xcp);
5541587Ssklower 				m_freem (m);
5641587Ssklower 				return;
5741587Ssklower 			}
5841587Ssklower 			if (hdp->hd_xcp == xcp)
5941587Ssklower 				break;
6041587Ssklower 		}
6141587Ssklower 		lastxcp = xcp;
6241587Ssklower 		lasthdp = hdp;
6341587Ssklower 	}
6441587Ssklower 
6541587Ssklower 	if (hdp->hd_state != ABM) {
6641587Ssklower 		m_freem (m);
6741587Ssklower 		return;
6841587Ssklower 	}
6941587Ssklower 
7041587Ssklower 	/*
7141587Ssklower 	 * Make room for the hdlc header either by prepending
7241587Ssklower 	 * another mbuf, or by adjusting the offset and length
7341587Ssklower 	 * of the first mbuf in the mbuf chain.
7441587Ssklower 	 */
7541587Ssklower 
7641587Ssklower 	if (m->m_off < MMINOFF + HDHEADERLN) {
7741587Ssklower 		register struct mbuf *m0;
7841587Ssklower 
7941587Ssklower 		m0 = m_get (M_DONTWAIT, MT_DATA);
8041587Ssklower 		if (m0 == NULL) {
8141587Ssklower 			m_freem (m);
8241587Ssklower 			return;
8341587Ssklower 		}
8441587Ssklower 		m0->m_next = m;
8541587Ssklower 		m0->m_len = HDHEADERLN;
8641587Ssklower 		m = m0;
8741587Ssklower 	} else {
8841587Ssklower 		m->m_off -= HDHEADERLN;
8941587Ssklower 		m->m_len += HDHEADERLN;
9041587Ssklower 	}
9141587Ssklower 
9241587Ssklower 	hd_append (&hdp->hd_txq, m);
9341587Ssklower 	hd_start (hdp);
9441587Ssklower }
9541587Ssklower 
9641587Ssklower hd_start (hdp)
9741587Ssklower register struct hdcb *hdp;
9841587Ssklower {
9941587Ssklower 	register struct mbuf *m;
10041587Ssklower 
10141587Ssklower 	/*
10241587Ssklower 	 * The iframe is only transmitted if all these conditions are FALSE.
10341587Ssklower 	 * The iframe remains queued (hdp->hd_txq) however and will be
10441587Ssklower 	 * transmitted as soon as these conditions are cleared.
10541587Ssklower 	 */
10641587Ssklower 
10741587Ssklower 	while (!(hdp->hd_condition & (TIMER_RECOVERY_CONDITION | REMOTE_RNR_CONDITION | REJ_CONDITION))) {
10841587Ssklower 		if (hdp->hd_vs == (hdp->hd_lastrxnr + hdp->hd_xcp->xc_lwsize) % MODULUS) {
10941587Ssklower 
11041587Ssklower 			/* We have now exceeded the  maximum  number  of
11141587Ssklower 			   outstanding iframes. Therefore,  we must wait
11241587Ssklower 			   until  at least  one is acknowledged if this
11341587Ssklower 			   condition  is not  turned off before we are
11441587Ssklower 			   requested to write another iframe. */
11541587Ssklower 			hdp->hd_window_condition++;
11641587Ssklower 			break;
11741587Ssklower 		}
11841587Ssklower 
11941587Ssklower 		/* hd_remove top iframe from transmit queue. */
12041587Ssklower 		if ((m = hd_remove (&hdp->hd_txq)) == NULL)
12141587Ssklower 			break;
12241587Ssklower 
12341587Ssklower 		hd_send_iframe (hdp, m, POLLOFF);
12441587Ssklower 	}
12541587Ssklower }
12641587Ssklower 
12741587Ssklower /*
12841587Ssklower  *  This procedure is passed a buffer descriptor for an iframe. It builds
12941587Ssklower  *  the rest of the control part of the frame and then writes it out.  It
13041587Ssklower  *  also  starts the  acknowledgement  timer and keeps  the iframe in the
13141587Ssklower  *  Retransmit queue (Retxq) just in case  we have to do this again.
13241587Ssklower  *
13341587Ssklower  *  Note: This routine is also called from hd_input.c when retransmission
13441587Ssklower  *       of old frames is required.
13541587Ssklower  */
13641587Ssklower 
13741587Ssklower hd_send_iframe (hdp, buf, poll_bit)
13841587Ssklower register struct hdcb *hdp;
13941587Ssklower register struct mbuf *buf;
14041587Ssklower int poll_bit;
14141587Ssklower {
14241587Ssklower 	register struct Hdlc_iframe *iframe;
14341587Ssklower 	register struct ifnet *ifp = hdp->hd_ifp;
14441587Ssklower 	struct mbuf *m;
14541587Ssklower 
14641587Ssklower 	KILL_TIMER (hdp);
14741587Ssklower 
14841587Ssklower 	if (buf == 0) {
14941587Ssklower 		printf ("hd_send_iframe: zero arg\n");
15041587Ssklower #ifdef HDLCDEBUG
15141587Ssklower 		hd_status (hdp);
15241587Ssklower 		hd_dumptrace (hdp);
15341587Ssklower #endif
15441587Ssklower 		hdp->hd_vs = (hdp->hd_vs + 7) % MODULUS;
15541587Ssklower 		return;
15641587Ssklower 	}
15741587Ssklower 	iframe = mtod (buf, struct Hdlc_iframe *);
15841587Ssklower 
15941587Ssklower 	iframe -> hdlc_0 = 0;
16041587Ssklower 	iframe -> nr = hdp->hd_vr;
16141587Ssklower 	iframe -> pf = poll_bit;
16241587Ssklower 	iframe -> ns = hdp->hd_vs;
16341587Ssklower 	iframe -> address = ADDRESS_B;
16441587Ssklower 	hdp->hd_lasttxnr = hdp->hd_vr;
16541587Ssklower 	hdp->hd_rrtimer = 0;
16641587Ssklower 
16741587Ssklower 	if (hdp->hd_vs == hdp->hd_retxqi) {
16841587Ssklower 		/* Check for retransmissions. */
16941587Ssklower 		/* Put iframe only once in the Retransmission queue. */
17041587Ssklower 		hdp->hd_retxq[hdp->hd_retxqi] = buf;
17141587Ssklower 		hdp->hd_retxqi = (hdp->hd_retxqi + 1) % MODULUS;
17241587Ssklower 		hdp->hd_iframes_out++;
17341587Ssklower 	}
17441587Ssklower 
17541587Ssklower 	hdp->hd_vs = (hdp->hd_vs + 1) % MODULUS;
17641587Ssklower 
17741587Ssklower 	hd_trace (hdp, TX, (struct Hdlc_frame *)iframe);
17841587Ssklower 
17941587Ssklower 	/* Write buffer on device. */
18041587Ssklower 	m = hdp->hd_dontcopy ? buf : m_copy(buf, 0, (int)M_COPYALL);
18141587Ssklower 	if (m == 0) {
18241587Ssklower 		printf("hdlc: out of mbufs\n");
18341587Ssklower 		return;
18441587Ssklower 	}
18541587Ssklower 	(*ifp -> if_output) (ifp, m, (struct sockaddr *)hdp->hd_xcp);
18641587Ssklower 
18741587Ssklower 	SET_TIMER (hdp);
18841587Ssklower }
18941587Ssklower 
19041587Ssklower /*
19141587Ssklower  *  This routine gets control when the timer expires because we have not
19241587Ssklower  *  received an acknowledgement for a iframe.
19341587Ssklower  */
19441587Ssklower 
19541587Ssklower hd_resend_iframe (hdp)
19641587Ssklower register struct hdcb *hdp;
19741587Ssklower {
19841587Ssklower 
19941587Ssklower 	if (hdp->hd_retxcnt++ < hd_n2) {
20041587Ssklower 		if (!(hdp->hd_condition & TIMER_RECOVERY_CONDITION)) {
20141587Ssklower 			hdp->hd_xx = hdp->hd_vs;
20241587Ssklower 			hdp->hd_condition |= TIMER_RECOVERY_CONDITION;
20341587Ssklower 		}
20441587Ssklower 
20541587Ssklower 		hdp->hd_vs = hdp->hd_lastrxnr;
20641587Ssklower 		hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], POLLON);
20741587Ssklower 	} else {
20841587Ssklower 		/* At this point we have not received a RR even after N2
20941587Ssklower 		   retries - attempt to reset link. */
21041587Ssklower 
21141587Ssklower 		hd_initvars (hdp);
21241587Ssklower 		hd_writeinternal (hdp, SABM, POLLOFF);
21341587Ssklower 		hdp->hd_state = WAIT_UA;
21441587Ssklower 		SET_TIMER (hdp);
21541587Ssklower 		hd_message (hdp, "Timer recovery failed: link down");
21641587Ssklower 		(void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_xcp);
21741587Ssklower 	}
21841587Ssklower }
219