xref: /original-bsd/sys/netccitt/llc_output.c (revision 35274bea)
1 /*
2  * Copyright (C) Dirk Husemann, Computer Science Department IV,
3  * 		 University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992
4  * Copyright (c) 1992, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Dirk Husemann and the Computer Science Department (IV) of
9  * the University of Erlangen-Nuremberg, Germany.
10  *
11  * %sccs.include.redist.c%
12  *
13  *	@(#)llc_output.c	8.1 (Berkeley) 06/10/93
14  */
15 
16 #include <sys/param.h>
17 #include <sys/systm.h>
18 #include <sys/mbuf.h>
19 #include <sys/domain.h>
20 #include <sys/socket.h>
21 #include <sys/protosw.h>
22 #include <sys/errno.h>
23 #include <sys/time.h>
24 #include <sys/kernel.h>
25 
26 #include <net/if.h>
27 #include <net/if_dl.h>
28 #include <net/if_llc.h>
29 #include <net/route.h>
30 
31 #include <netccitt/dll.h>
32 #include <netccitt/llc_var.h>
33 
34 /*
35  * llc_output() --- called by an upper layer (network layer) entity whenever
36  *                  there is an INFO frame to be transmitted. We enqueue the
37  *                  info frame and call llc_start() to do the actual sending.
38  */
39 
llc_output(struct llc_linkcb * linkp,struct mbuf * m)40 llc_output(struct llc_linkcb *linkp, struct mbuf *m)
41 {
42 	register int i;
43 
44 	i = splimp();
45 	LLC_ENQUEUE(linkp, m);
46 	llc_start(linkp);
47 	splx(i);
48 
49 }
50 
51 
52 /*
53  * llc_start() --- We try to subsequently dequeue all the frames available and
54  *                 send them out.
55  */
56 void
llc_start(struct llc_linkcb * linkp)57 llc_start(struct llc_linkcb *linkp)
58 {
59 	register int i;
60 	register struct mbuf *m;
61 	int action;
62 
63 	while ((LLC_STATEEQ(linkp, NORMAL) || LLC_STATEEQ(linkp, BUSY) ||
64 		LLC_STATEEQ(linkp, REJECT)) &&
65 	       (linkp->llcl_slotsfree > 0) &&
66 	       (LLC_GETFLAG(linkp, REMOTE_BUSY) == 0)) {
67 		LLC_DEQUEUE(linkp, m);
68 		if (m == NULL)
69 			break;
70 		LLC_SETFRAME(linkp, m);
71 		(void)llc_statehandler(linkp, (struct llc *) 0, NL_DATA_REQUEST,
72 				       0, 0);
73 	}
74 }
75 
76 
77 /*
78  * llc_send() --- Handles single frames. If dealing with INFO frames we need to
79  *                prepend the LLC header, otherwise we just allocate an mbuf.
80  *                In both cases the actual send is done by llc_rawsend().
81  */
llc_send(struct llc_linkcb * linkp,int frame_kind,int cmdrsp,int pollfinal)82 llc_send(struct llc_linkcb *linkp, int frame_kind, int cmdrsp, int pollfinal)
83 {
84 	register struct mbuf *m = (struct mbuf *)0;
85 	register struct llc *frame;
86 
87 	if (frame_kind == LLCFT_INFO)
88 		m = linkp->llcl_output_buffers[llc_seq2slot(linkp,
89 							    linkp->llcl_vs)];
90 	LLC_GETHDR(frame, m);
91 
92 	/* pass it on to llc_rawsend() */
93 	llc_rawsend(linkp, m, frame, frame_kind, linkp->llcl_vs, cmdrsp, pollfinal);
94 
95 	if (frame_kind == LLCFT_INFO)
96 		LLC_INC(linkp->llcl_vs);
97 
98 	return 0;
99 }
100 
101 /*
102  * llc_resend() --- llc_resend() retransmits all unacknowledged INFO frames.
103  */
llc_resend(struct llc_linkcb * linkp,int cmdrsp,int pollfinal)104 llc_resend(struct llc_linkcb *linkp, int cmdrsp, int pollfinal)
105 {
106 	register struct llc *frame;
107 	register struct mbuf *m;
108 	register int seq, slot;
109 
110 	if (linkp->llcl_slotsfree < linkp->llcl_window)
111 		/* assert lock between nr_received & V(S) */
112 		if (linkp->llcl_nr_received != linkp->llcl_vs)
113 			panic("llc: V(S) != N(R) received\n");
114 
115 		for (slot = llc_seq2slot(linkp, linkp->llcl_vs);
116 		     slot != linkp->llcl_freeslot;
117 		     LLC_INC(linkp->llcl_vs),
118 		     slot = llc_seq2slot(linkp, linkp->llcl_vs)) {
119 			m = linkp->llcl_output_buffers[slot];
120 			LLC_GETHDR(frame, m);
121 			llc_rawsend(linkp, m, frame, LLCFT_INFO, linkp->llcl_vs,
122 				    cmdrsp, pollfinal);
123 			pollfinal = 0;
124 		}
125 
126 	return 0;
127 }
128 
129 /*
130  * llc_rawsend() --- constructs an LLC frame and sends it out via the
131  *                   associated interface of the link control block.
132  *
133  * We need to make sure that outgoing frames have the correct length,
134  * in particular the 4 byte ones (RR, RNR, REJ) as LLC_GETHDR() will
135  * set the mbuf len to 3 as default len for non INFO frames ...
136  *
137  * Frame kind             Length (w/o MAC header, {D,S}SAP incl.)
138  * --------------------------------------------------------------
139  * DISC, SABME, UA, DM    3 bytes  ({D,S}SAP + CONTROL)
140  * RR, RNR, REJ           4 bytes  ({D,S}SAP + CONTROL0 + CONTROL1)
141  * XID                    6 bytes  ({D,S}SAP + CONTROL0 + FI,CLASS,WINDOW)
142  * FRMR                   7 bytes  ({D,S}SAP + CONTROL0 + REJ CONTROL,V(S),V(R),CAUSE)
143  * INFO                   4 -- MTU
144  * UI, TEST               3 -- MTU
145  *
146  */
147 #define LLC_SETLEN(m, l) (m)->m_pkthdr.len = (m)->m_len = (l)
148 
llc_rawsend(struct llc_linkcb * linkp,struct mbuf * m,struct llc * frame,int frame_kind,int vs,int cmdrsp,int pollfinal)149 llc_rawsend(struct llc_linkcb *linkp, struct mbuf *m, struct llc *frame,
150 	    int frame_kind, int vs, int cmdrsp, int pollfinal)
151 {
152 	register short adjust = LLC_UFRAMELEN;
153 	struct ifnet *ifp;
154 
155 	switch (frame_kind) {
156 	/* supervisory and information frames */
157 	case LLCFT_INFO:
158 		frame->llc_control = LLC_INFO;
159 		LLCSBITS(frame->llc_control, i_ns, vs);
160 		LLCSBITS(frame->llc_control_ext, i_nr, linkp->llcl_vr);
161 		adjust = LLC_ISFRAMELEN;
162 		break;
163 	case LLCFT_RR:
164 		frame->llc_control = LLC_RR;
165 		LLC_SETLEN(m, LLC_ISFRAMELEN);
166 		LLCSBITS(frame->llc_control_ext, s_nr, linkp->llcl_vr);
167 		adjust = LLC_ISFRAMELEN;
168 		break;
169 	case LLCFT_RNR:
170 		frame->llc_control = LLC_RNR;
171 		LLC_SETLEN(m, LLC_ISFRAMELEN);
172 		LLCSBITS(frame->llc_control_ext, s_nr, linkp->llcl_vr);
173 		adjust = LLC_ISFRAMELEN;
174 		break;
175 	case LLCFT_REJ:
176 		frame->llc_control = LLC_REJ;
177 		LLC_SETLEN(m, LLC_ISFRAMELEN);
178 		LLCSBITS(frame->llc_control_ext, s_nr, linkp->llcl_vr);
179 		adjust = LLC_ISFRAMELEN;
180 		break;
181 	/* unnumbered frames */
182 	case LLCFT_DM:
183 		frame->llc_control = LLC_DM;
184 		break;
185 	case LLCFT_SABME:
186 		frame->llc_control = LLC_SABME;
187 		break;
188 	case LLCFT_DISC:
189 		frame->llc_control = LLC_DISC;
190 		break;
191 	case LLCFT_UA:
192 		frame->llc_control = LLC_UA;
193 		break;
194 	case LLCFT_UI:
195 		frame->llc_control = LLC_UI;
196 		break;
197 	case LLCFT_FRMR:
198 		frame->llc_control = LLC_FRMR;
199 		/* get more space --- FRMR frame are longer then usual */
200 		LLC_SETLEN(m, LLC_FRMRLEN);
201 		bcopy((caddr_t) &linkp->llcl_frmrinfo,
202 		      (caddr_t) &frame->llc_frmrinfo,
203 		      sizeof(struct frmrinfo));
204 		break;
205 	default:
206 		/*
207 		 * We don't send {XID, TEST} frames
208 		 */
209 		if (m)
210 			m_freem(m);
211 		return;
212 	}
213 
214 	/*
215 	 * Fill in DSAP/SSAP
216 	 */
217 	frame->llc_dsap = frame->llc_ssap = LLSAPADDR(&linkp->llcl_addr);
218 	frame->llc_ssap |= cmdrsp;
219 
220 	/*
221 	 * Check for delayed action pending. ISO 8802-2, 7.9.2 (5)
222 	 * and ISO 8802-2, 7.9.2.3 (32), (34), (36) pertain to this
223 	 * piece of code --- hopefully we got it right here (i.e.
224 	 * in the spirit of (32), (34), and (36) ...
225 	 */
226 	switch (frame_kind) {
227 	case LLCFT_RR:
228 	case LLCFT_RNR:
229 	case LLCFT_REJ:
230 	case LLCFT_INFO:
231 		switch (LLC_GETFLAG(linkp, DACTION)) {
232 		case LLC_DACKCMD:
233 		case LLC_DACKRSP:
234 			LLC_STOPTIMER(linkp, DACTION);
235 			break;
236 		case LLC_DACKCMDPOLL:
237 			if (cmdrsp == LLC_CMD) {
238 				pollfinal = 1;
239 				LLC_STOPTIMER(linkp, DACTION);
240 			}
241 			break;
242 		case LLC_DACKRSPFINAL:
243 			if (cmdrsp == LLC_RSP) {
244 				pollfinal = 1;
245 				LLC_STOPTIMER(linkp, DACTION);
246 			}
247 			break;
248 		}
249 		break;
250 	}
251 
252 	if (adjust == LLC_UFRAMELEN)
253 		LLCSBITS(frame->llc_control, u_pf, pollfinal);
254 	else LLCSBITS(frame->llc_control_ext, s_pf, pollfinal);
255 
256 	/*
257 	 * Get interface to send frame onto
258 	 */
259 	ifp = linkp->llcl_if;
260 	if (frame_kind == LLCFT_INFO) {
261 		/*
262 		 * send out a copy of the frame, retain the
263 		 * original
264 		 */
265 		(*ifp->if_output)(ifp, m_copy(m, 0, (int)M_COPYALL),
266 				  rt_key(linkp->llcl_nlrt),
267 				  linkp->llcl_nlrt);
268 		/*
269 		 * Account for the LLC header and let it ``disappear''
270 		 * as the raw info frame payload is what we hold in
271 		 * the output_buffers of the link.
272 		 */
273 		m_adj(m, LLC_ISFRAMELEN);
274 	} else (*ifp->if_output)(ifp, m,
275 				 rt_key(linkp->llcl_nlrt),
276 				 linkp->llcl_nlrt);
277 }
278 
279