xref: /csrg-svn/sys/netccitt/hd_output.c (revision 43361)
141703Ssklower /*
241703Ssklower  * Copyright (c) University of British Columbia, 1984
341703Ssklower  * Copyright (c) 1990 The Regents of the University of California.
441703Ssklower  * 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*43361Ssklower  *	@(#)hd_output.c	7.3 (Berkeley) 06/21/90
1341703Ssklower  */
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 
38*43361Ssklower hd_output (m, info)
3941587Ssklower register struct mbuf *m;
40*43361Ssklower caddr_t	info;
4141587Ssklower {
42*43361Ssklower 	register struct hdcb *hdp = (struct hdcb *)info;
43*43361Ssklower 	struct x25config *xcp;
4441587Ssklower 
4541587Ssklower 	if (m == NULL)
4641587Ssklower 		panic ("hd_output");
4741587Ssklower 
4841587Ssklower 	if (hdp->hd_state != ABM) {
4941587Ssklower 		m_freem (m);
5041587Ssklower 		return;
5141587Ssklower 	}
5241587Ssklower 
5341587Ssklower 	/*
5441587Ssklower 	 * Make room for the hdlc header either by prepending
5541587Ssklower 	 * another mbuf, or by adjusting the offset and length
5641587Ssklower 	 * of the first mbuf in the mbuf chain.
5741587Ssklower 	 */
5841587Ssklower 
59*43361Ssklower 	M_PREPEND(m, M_DONTWAIT, HDHEADERLN);
60*43361Ssklower 	if (m == NULL)
61*43361Ssklower 		return;
6241587Ssklower 
6341587Ssklower 	hd_append (&hdp->hd_txq, m);
6441587Ssklower 	hd_start (hdp);
6541587Ssklower }
6641587Ssklower 
6741587Ssklower hd_start (hdp)
6841587Ssklower register struct hdcb *hdp;
6941587Ssklower {
7041587Ssklower 	register struct mbuf *m;
7141587Ssklower 
7241587Ssklower 	/*
7341587Ssklower 	 * The iframe is only transmitted if all these conditions are FALSE.
7441587Ssklower 	 * The iframe remains queued (hdp->hd_txq) however and will be
7541587Ssklower 	 * transmitted as soon as these conditions are cleared.
7641587Ssklower 	 */
7741587Ssklower 
7841587Ssklower 	while (!(hdp->hd_condition & (TIMER_RECOVERY_CONDITION | REMOTE_RNR_CONDITION | REJ_CONDITION))) {
7941587Ssklower 		if (hdp->hd_vs == (hdp->hd_lastrxnr + hdp->hd_xcp->xc_lwsize) % MODULUS) {
8041587Ssklower 
8141587Ssklower 			/* We have now exceeded the  maximum  number  of
8241587Ssklower 			   outstanding iframes. Therefore,  we must wait
8341587Ssklower 			   until  at least  one is acknowledged if this
8441587Ssklower 			   condition  is not  turned off before we are
8541587Ssklower 			   requested to write another iframe. */
8641587Ssklower 			hdp->hd_window_condition++;
8741587Ssklower 			break;
8841587Ssklower 		}
8941587Ssklower 
9041587Ssklower 		/* hd_remove top iframe from transmit queue. */
9141587Ssklower 		if ((m = hd_remove (&hdp->hd_txq)) == NULL)
9241587Ssklower 			break;
9341587Ssklower 
9441587Ssklower 		hd_send_iframe (hdp, m, POLLOFF);
9541587Ssklower 	}
9641587Ssklower }
9741587Ssklower 
9841587Ssklower /*
9941587Ssklower  *  This procedure is passed a buffer descriptor for an iframe. It builds
10041587Ssklower  *  the rest of the control part of the frame and then writes it out.  It
10141587Ssklower  *  also  starts the  acknowledgement  timer and keeps  the iframe in the
10241587Ssklower  *  Retransmit queue (Retxq) just in case  we have to do this again.
10341587Ssklower  *
10441587Ssklower  *  Note: This routine is also called from hd_input.c when retransmission
10541587Ssklower  *       of old frames is required.
10641587Ssklower  */
10741587Ssklower 
10841587Ssklower hd_send_iframe (hdp, buf, poll_bit)
10941587Ssklower register struct hdcb *hdp;
11041587Ssklower register struct mbuf *buf;
11141587Ssklower int poll_bit;
11241587Ssklower {
11341587Ssklower 	register struct Hdlc_iframe *iframe;
11441587Ssklower 	struct mbuf *m;
115*43361Ssklower 	int s
11641587Ssklower 
11741587Ssklower 	KILL_TIMER (hdp);
11841587Ssklower 
11941587Ssklower 	if (buf == 0) {
12041587Ssklower 		printf ("hd_send_iframe: zero arg\n");
12141587Ssklower #ifdef HDLCDEBUG
12241587Ssklower 		hd_status (hdp);
12341587Ssklower 		hd_dumptrace (hdp);
12441587Ssklower #endif
12541587Ssklower 		hdp->hd_vs = (hdp->hd_vs + 7) % MODULUS;
12641587Ssklower 		return;
12741587Ssklower 	}
12841587Ssklower 	iframe = mtod (buf, struct Hdlc_iframe *);
12941587Ssklower 
13041587Ssklower 	iframe -> hdlc_0 = 0;
13141587Ssklower 	iframe -> nr = hdp->hd_vr;
13241587Ssklower 	iframe -> pf = poll_bit;
13341587Ssklower 	iframe -> ns = hdp->hd_vs;
13441587Ssklower 	iframe -> address = ADDRESS_B;
13541587Ssklower 	hdp->hd_lasttxnr = hdp->hd_vr;
13641587Ssklower 	hdp->hd_rrtimer = 0;
13741587Ssklower 
13841587Ssklower 	if (hdp->hd_vs == hdp->hd_retxqi) {
13941587Ssklower 		/* Check for retransmissions. */
14041587Ssklower 		/* Put iframe only once in the Retransmission queue. */
14141587Ssklower 		hdp->hd_retxq[hdp->hd_retxqi] = buf;
14241587Ssklower 		hdp->hd_retxqi = (hdp->hd_retxqi + 1) % MODULUS;
14341587Ssklower 		hdp->hd_iframes_out++;
14441587Ssklower 	}
14541587Ssklower 
14641587Ssklower 	hdp->hd_vs = (hdp->hd_vs + 1) % MODULUS;
14741587Ssklower 
14841587Ssklower 	hd_trace (hdp, TX, (struct Hdlc_frame *)iframe);
14941587Ssklower 
15041587Ssklower 	/* Write buffer on device. */
15141587Ssklower 	m = hdp->hd_dontcopy ? buf : m_copy(buf, 0, (int)M_COPYALL);
15241587Ssklower 	if (m == 0) {
15341587Ssklower 		printf("hdlc: out of mbufs\n");
15441587Ssklower 		return;
15541587Ssklower 	}
156*43361Ssklower 	(*hdp->hd_output)(hdp, m);
15741587Ssklower 	SET_TIMER (hdp);
15841587Ssklower }
15941587Ssklower 
160*43361Ssklower hd_ifoutput(hdp, m)
161*43361Ssklower register struct hdcb *hdp;
162*43361Ssklower register struct mbuf *m;
163*43361Ssklower {
164*43361Ssklower 	/*
165*43361Ssklower 	 * Queue message on interface, and start output if interface
166*43361Ssklower 	 * not yet active.
167*43361Ssklower 	 */
168*43361Ssklower 	register struct ifnet *ifp = hdp->hdp_ifp;
169*43361Ssklower 	int s = splimp();
170*43361Ssklower 	if (IF_QFULL(&ifp->if_snd)) {
171*43361Ssklower 		IF_DROP(&ifp->if_snd);
172*43361Ssklower 		printf("%s%d: HDLC says OK to send but queue full, may hang\n",
173*43361Ssklower 			ifp->if_name, ifp->if_unit);
174*43361Ssklower 		m_freem(m);
175*43361Ssklower 	} else {
176*43361Ssklower 		IF_ENQUEUE(&ifp->if_snd, m);
177*43361Ssklower 		if ((ifp->if_flags & IFF_OACTIVE) == 0)
178*43361Ssklower 			(*ifp->if_start)(ifp);
179*43361Ssklower 	}
180*43361Ssklower 	splx(s);
181*43361Ssklower }
182*43361Ssklower 
183*43361Ssklower 
18441587Ssklower /*
18541587Ssklower  *  This routine gets control when the timer expires because we have not
18641587Ssklower  *  received an acknowledgement for a iframe.
18741587Ssklower  */
18841587Ssklower 
18941587Ssklower hd_resend_iframe (hdp)
19041587Ssklower register struct hdcb *hdp;
19141587Ssklower {
19241587Ssklower 
19341587Ssklower 	if (hdp->hd_retxcnt++ < hd_n2) {
19441587Ssklower 		if (!(hdp->hd_condition & TIMER_RECOVERY_CONDITION)) {
19541587Ssklower 			hdp->hd_xx = hdp->hd_vs;
19641587Ssklower 			hdp->hd_condition |= TIMER_RECOVERY_CONDITION;
19741587Ssklower 		}
19841587Ssklower 
19941587Ssklower 		hdp->hd_vs = hdp->hd_lastrxnr;
20041587Ssklower 		hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], POLLON);
20141587Ssklower 	} else {
20241587Ssklower 		/* At this point we have not received a RR even after N2
20341587Ssklower 		   retries - attempt to reset link. */
20441587Ssklower 
20541587Ssklower 		hd_initvars (hdp);
20641587Ssklower 		hd_writeinternal (hdp, SABM, POLLOFF);
20741587Ssklower 		hdp->hd_state = WAIT_UA;
20841587Ssklower 		SET_TIMER (hdp);
20941587Ssklower 		hd_message (hdp, "Timer recovery failed: link down");
21041587Ssklower 		(void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_xcp);
21141587Ssklower 	}
21241587Ssklower }
213