xref: /csrg-svn/sys/netccitt/hd_output.c (revision 41587)
1*41587Ssklower /* Copyright (c) University of British Columbia, 1984 */
2*41587Ssklower 
3*41587Ssklower #include "../h/param.h"
4*41587Ssklower #include "../h/systm.h"
5*41587Ssklower #include "../h/mbuf.h"
6*41587Ssklower #include "../h/domain.h"
7*41587Ssklower #include "../h/socket.h"
8*41587Ssklower #include "../h/protosw.h"
9*41587Ssklower #include "../h/errno.h"
10*41587Ssklower #include "../h/time.h"
11*41587Ssklower #include "../h/kernel.h"
12*41587Ssklower #include "../net/if.h"
13*41587Ssklower 
14*41587Ssklower #include "../netccitt/hdlc.h"
15*41587Ssklower #include "../netccitt/hd_var.h"
16*41587Ssklower #include "../netccitt/x25.h"
17*41587Ssklower 
18*41587Ssklower /*
19*41587Ssklower  *      HDLC OUTPUT INTERFACE
20*41587Ssklower  *
21*41587Ssklower  *      This routine is called when the X.25 packet layer output routine
22*41587Ssklower  *      has a information frame (iframe)  to write.   It is  also called
23*41587Ssklower  *      by the input and control routines of the HDLC layer.
24*41587Ssklower  */
25*41587Ssklower 
26*41587Ssklower hd_output (m, xcp)
27*41587Ssklower struct x25config *xcp;
28*41587Ssklower register struct mbuf *m;
29*41587Ssklower {
30*41587Ssklower 	register struct hdcb *hdp;
31*41587Ssklower 	static struct x25config *lastxcp;
32*41587Ssklower 	static struct hdcb *lasthdp;
33*41587Ssklower 
34*41587Ssklower 	if (m == NULL)
35*41587Ssklower 		panic ("hd_output");
36*41587Ssklower 
37*41587Ssklower 	if (xcp == lastxcp)
38*41587Ssklower 		hdp = lasthdp;
39*41587Ssklower 	else {
40*41587Ssklower 		for (hdp = hdcbhead; ; hdp = hdp->hd_next) {
41*41587Ssklower 			if (hdp == 0) {
42*41587Ssklower 				printf("hd_output: can't find hdcb for %X\n", xcp);
43*41587Ssklower 				m_freem (m);
44*41587Ssklower 				return;
45*41587Ssklower 			}
46*41587Ssklower 			if (hdp->hd_xcp == xcp)
47*41587Ssklower 				break;
48*41587Ssklower 		}
49*41587Ssklower 		lastxcp = xcp;
50*41587Ssklower 		lasthdp = hdp;
51*41587Ssklower 	}
52*41587Ssklower 
53*41587Ssklower 	if (hdp->hd_state != ABM) {
54*41587Ssklower 		m_freem (m);
55*41587Ssklower 		return;
56*41587Ssklower 	}
57*41587Ssklower 
58*41587Ssklower 	/*
59*41587Ssklower 	 * Make room for the hdlc header either by prepending
60*41587Ssklower 	 * another mbuf, or by adjusting the offset and length
61*41587Ssklower 	 * of the first mbuf in the mbuf chain.
62*41587Ssklower 	 */
63*41587Ssklower 
64*41587Ssklower 	if (m->m_off < MMINOFF + HDHEADERLN) {
65*41587Ssklower 		register struct mbuf *m0;
66*41587Ssklower 
67*41587Ssklower 		m0 = m_get (M_DONTWAIT, MT_DATA);
68*41587Ssklower 		if (m0 == NULL) {
69*41587Ssklower 			m_freem (m);
70*41587Ssklower 			return;
71*41587Ssklower 		}
72*41587Ssklower 		m0->m_next = m;
73*41587Ssklower 		m0->m_len = HDHEADERLN;
74*41587Ssklower 		m = m0;
75*41587Ssklower 	} else {
76*41587Ssklower 		m->m_off -= HDHEADERLN;
77*41587Ssklower 		m->m_len += HDHEADERLN;
78*41587Ssklower 	}
79*41587Ssklower 
80*41587Ssklower 	hd_append (&hdp->hd_txq, m);
81*41587Ssklower 	hd_start (hdp);
82*41587Ssklower }
83*41587Ssklower 
84*41587Ssklower hd_start (hdp)
85*41587Ssklower register struct hdcb *hdp;
86*41587Ssklower {
87*41587Ssklower 	register struct mbuf *m;
88*41587Ssklower 
89*41587Ssklower 	/*
90*41587Ssklower 	 * The iframe is only transmitted if all these conditions are FALSE.
91*41587Ssklower 	 * The iframe remains queued (hdp->hd_txq) however and will be
92*41587Ssklower 	 * transmitted as soon as these conditions are cleared.
93*41587Ssklower 	 */
94*41587Ssklower 
95*41587Ssklower 	while (!(hdp->hd_condition & (TIMER_RECOVERY_CONDITION | REMOTE_RNR_CONDITION | REJ_CONDITION))) {
96*41587Ssklower 		if (hdp->hd_vs == (hdp->hd_lastrxnr + hdp->hd_xcp->xc_lwsize) % MODULUS) {
97*41587Ssklower 
98*41587Ssklower 			/* We have now exceeded the  maximum  number  of
99*41587Ssklower 			   outstanding iframes. Therefore,  we must wait
100*41587Ssklower 			   until  at least  one is acknowledged if this
101*41587Ssklower 			   condition  is not  turned off before we are
102*41587Ssklower 			   requested to write another iframe. */
103*41587Ssklower 			hdp->hd_window_condition++;
104*41587Ssklower 			break;
105*41587Ssklower 		}
106*41587Ssklower 
107*41587Ssklower 		/* hd_remove top iframe from transmit queue. */
108*41587Ssklower 		if ((m = hd_remove (&hdp->hd_txq)) == NULL)
109*41587Ssklower 			break;
110*41587Ssklower 
111*41587Ssklower 		hd_send_iframe (hdp, m, POLLOFF);
112*41587Ssklower 	}
113*41587Ssklower }
114*41587Ssklower 
115*41587Ssklower /*
116*41587Ssklower  *  This procedure is passed a buffer descriptor for an iframe. It builds
117*41587Ssklower  *  the rest of the control part of the frame and then writes it out.  It
118*41587Ssklower  *  also  starts the  acknowledgement  timer and keeps  the iframe in the
119*41587Ssklower  *  Retransmit queue (Retxq) just in case  we have to do this again.
120*41587Ssklower  *
121*41587Ssklower  *  Note: This routine is also called from hd_input.c when retransmission
122*41587Ssklower  *       of old frames is required.
123*41587Ssklower  */
124*41587Ssklower 
125*41587Ssklower hd_send_iframe (hdp, buf, poll_bit)
126*41587Ssklower register struct hdcb *hdp;
127*41587Ssklower register struct mbuf *buf;
128*41587Ssklower int poll_bit;
129*41587Ssklower {
130*41587Ssklower 	register struct Hdlc_iframe *iframe;
131*41587Ssklower 	register struct ifnet *ifp = hdp->hd_ifp;
132*41587Ssklower 	struct mbuf *m;
133*41587Ssklower 
134*41587Ssklower 	KILL_TIMER (hdp);
135*41587Ssklower 
136*41587Ssklower 	if (buf == 0) {
137*41587Ssklower 		printf ("hd_send_iframe: zero arg\n");
138*41587Ssklower #ifdef HDLCDEBUG
139*41587Ssklower 		hd_status (hdp);
140*41587Ssklower 		hd_dumptrace (hdp);
141*41587Ssklower #endif
142*41587Ssklower 		hdp->hd_vs = (hdp->hd_vs + 7) % MODULUS;
143*41587Ssklower 		return;
144*41587Ssklower 	}
145*41587Ssklower 	iframe = mtod (buf, struct Hdlc_iframe *);
146*41587Ssklower 
147*41587Ssklower 	iframe -> hdlc_0 = 0;
148*41587Ssklower 	iframe -> nr = hdp->hd_vr;
149*41587Ssklower 	iframe -> pf = poll_bit;
150*41587Ssklower 	iframe -> ns = hdp->hd_vs;
151*41587Ssklower 	iframe -> address = ADDRESS_B;
152*41587Ssklower 	hdp->hd_lasttxnr = hdp->hd_vr;
153*41587Ssklower 	hdp->hd_rrtimer = 0;
154*41587Ssklower 
155*41587Ssklower 	if (hdp->hd_vs == hdp->hd_retxqi) {
156*41587Ssklower 		/* Check for retransmissions. */
157*41587Ssklower 		/* Put iframe only once in the Retransmission queue. */
158*41587Ssklower 		hdp->hd_retxq[hdp->hd_retxqi] = buf;
159*41587Ssklower 		hdp->hd_retxqi = (hdp->hd_retxqi + 1) % MODULUS;
160*41587Ssklower 		hdp->hd_iframes_out++;
161*41587Ssklower 	}
162*41587Ssklower 
163*41587Ssklower 	hdp->hd_vs = (hdp->hd_vs + 1) % MODULUS;
164*41587Ssklower 
165*41587Ssklower 	hd_trace (hdp, TX, (struct Hdlc_frame *)iframe);
166*41587Ssklower 
167*41587Ssklower 	/* Write buffer on device. */
168*41587Ssklower 	m = hdp->hd_dontcopy ? buf : m_copy(buf, 0, (int)M_COPYALL);
169*41587Ssklower 	if (m == 0) {
170*41587Ssklower 		printf("hdlc: out of mbufs\n");
171*41587Ssklower 		return;
172*41587Ssklower 	}
173*41587Ssklower 	(*ifp -> if_output) (ifp, m, (struct sockaddr *)hdp->hd_xcp);
174*41587Ssklower 
175*41587Ssklower 	SET_TIMER (hdp);
176*41587Ssklower }
177*41587Ssklower 
178*41587Ssklower /*
179*41587Ssklower  *  This routine gets control when the timer expires because we have not
180*41587Ssklower  *  received an acknowledgement for a iframe.
181*41587Ssklower  */
182*41587Ssklower 
183*41587Ssklower hd_resend_iframe (hdp)
184*41587Ssklower register struct hdcb *hdp;
185*41587Ssklower {
186*41587Ssklower 
187*41587Ssklower 	if (hdp->hd_retxcnt++ < hd_n2) {
188*41587Ssklower 		if (!(hdp->hd_condition & TIMER_RECOVERY_CONDITION)) {
189*41587Ssklower 			hdp->hd_xx = hdp->hd_vs;
190*41587Ssklower 			hdp->hd_condition |= TIMER_RECOVERY_CONDITION;
191*41587Ssklower 		}
192*41587Ssklower 
193*41587Ssklower 		hdp->hd_vs = hdp->hd_lastrxnr;
194*41587Ssklower 		hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], POLLON);
195*41587Ssklower 	} else {
196*41587Ssklower 		/* At this point we have not received a RR even after N2
197*41587Ssklower 		   retries - attempt to reset link. */
198*41587Ssklower 
199*41587Ssklower 		hd_initvars (hdp);
200*41587Ssklower 		hd_writeinternal (hdp, SABM, POLLOFF);
201*41587Ssklower 		hdp->hd_state = WAIT_UA;
202*41587Ssklower 		SET_TIMER (hdp);
203*41587Ssklower 		hd_message (hdp, "Timer recovery failed: link down");
204*41587Ssklower 		(void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_xcp);
205*41587Ssklower 	}
206*41587Ssklower }
207