xref: /csrg-svn/sys/netccitt/llc_output.c (revision 63216)
157027Ssklower /*
257027Ssklower  * Copyright (C) Dirk Husemann, Computer Science Department IV,
357027Ssklower  * 		 University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992
4*63216Sbostic  * Copyright (c) 1992, 1993
5*63216Sbostic  *	The Regents of the University of California.  All rights reserved.
657027Ssklower  *
757027Ssklower  * This code is derived from software contributed to Berkeley by
857027Ssklower  * Dirk Husemann and the Computer Science Department (IV) of
957027Ssklower  * the University of Erlangen-Nuremberg, Germany.
1057027Ssklower  *
1157027Ssklower  * %sccs.include.redist.c%
1257027Ssklower  *
13*63216Sbostic  *	@(#)llc_output.c	8.1 (Berkeley) 06/10/93
1457027Ssklower  */
1557027Ssklower 
1657027Ssklower #include <sys/param.h>
1757027Ssklower #include <sys/systm.h>
1857027Ssklower #include <sys/mbuf.h>
1957027Ssklower #include <sys/domain.h>
2057027Ssklower #include <sys/socket.h>
2157027Ssklower #include <sys/protosw.h>
2257027Ssklower #include <sys/errno.h>
2357027Ssklower #include <sys/time.h>
2457027Ssklower #include <sys/kernel.h>
2557027Ssklower 
2657027Ssklower #include <net/if.h>
2757027Ssklower #include <net/if_dl.h>
2857027Ssklower #include <net/if_llc.h>
2957027Ssklower #include <net/route.h>
3057027Ssklower 
3157027Ssklower #include <netccitt/dll.h>
3257027Ssklower #include <netccitt/llc_var.h>
3357027Ssklower 
3457027Ssklower /*
3557027Ssklower  * llc_output() --- called by an upper layer (network layer) entity whenever
3657027Ssklower  *                  there is an INFO frame to be transmitted. We enqueue the
3757027Ssklower  *                  info frame and call llc_start() to do the actual sending.
3857027Ssklower  */
3957027Ssklower 
llc_output(struct llc_linkcb * linkp,struct mbuf * m)4057027Ssklower llc_output(struct llc_linkcb *linkp, struct mbuf *m)
4157027Ssklower {
4257027Ssklower 	register int i;
4357027Ssklower 
4457027Ssklower 	i = splimp();
4557027Ssklower 	LLC_ENQUEUE(linkp, m);
4657027Ssklower 	llc_start(linkp);
4757027Ssklower 	splx(i);
4857027Ssklower 
4957027Ssklower }
5057027Ssklower 
5157027Ssklower 
5257027Ssklower /*
5357027Ssklower  * llc_start() --- We try to subsequently dequeue all the frames available and
5457027Ssklower  *                 send them out.
5557027Ssklower  */
5657027Ssklower void
llc_start(struct llc_linkcb * linkp)5757027Ssklower llc_start(struct llc_linkcb *linkp)
5857027Ssklower {
5957027Ssklower 	register int i;
6057027Ssklower 	register struct mbuf *m;
6157027Ssklower 	int action;
6257027Ssklower 
6357027Ssklower 	while ((LLC_STATEEQ(linkp, NORMAL) || LLC_STATEEQ(linkp, BUSY) ||
6457027Ssklower 		LLC_STATEEQ(linkp, REJECT)) &&
6557027Ssklower 	       (linkp->llcl_slotsfree > 0) &&
6657027Ssklower 	       (LLC_GETFLAG(linkp, REMOTE_BUSY) == 0)) {
6757027Ssklower 		LLC_DEQUEUE(linkp, m);
6857027Ssklower 		if (m == NULL)
6957027Ssklower 			break;
7057027Ssklower 		LLC_SETFRAME(linkp, m);
7157027Ssklower 		(void)llc_statehandler(linkp, (struct llc *) 0, NL_DATA_REQUEST,
7257027Ssklower 				       0, 0);
7357027Ssklower 	}
7457027Ssklower }
7557027Ssklower 
7657027Ssklower 
7757027Ssklower /*
7857027Ssklower  * llc_send() --- Handles single frames. If dealing with INFO frames we need to
7957027Ssklower  *                prepend the LLC header, otherwise we just allocate an mbuf.
8057027Ssklower  *                In both cases the actual send is done by llc_rawsend().
8157027Ssklower  */
llc_send(struct llc_linkcb * linkp,int frame_kind,int cmdrsp,int pollfinal)8257027Ssklower llc_send(struct llc_linkcb *linkp, int frame_kind, int cmdrsp, int pollfinal)
8357027Ssklower {
8457027Ssklower 	register struct mbuf *m = (struct mbuf *)0;
8557027Ssklower 	register struct llc *frame;
8657027Ssklower 
8757027Ssklower 	if (frame_kind == LLCFT_INFO)
8857027Ssklower 		m = linkp->llcl_output_buffers[llc_seq2slot(linkp,
8957027Ssklower 							    linkp->llcl_vs)];
9057027Ssklower 	LLC_GETHDR(frame, m);
9157027Ssklower 
9257027Ssklower 	/* pass it on to llc_rawsend() */
9357027Ssklower 	llc_rawsend(linkp, m, frame, frame_kind, linkp->llcl_vs, cmdrsp, pollfinal);
9457027Ssklower 
9557027Ssklower 	if (frame_kind == LLCFT_INFO)
9657027Ssklower 		LLC_INC(linkp->llcl_vs);
9757027Ssklower 
9857027Ssklower 	return 0;
9957027Ssklower }
10057027Ssklower 
10157027Ssklower /*
10257027Ssklower  * llc_resend() --- llc_resend() retransmits all unacknowledged INFO frames.
10357027Ssklower  */
llc_resend(struct llc_linkcb * linkp,int cmdrsp,int pollfinal)10457027Ssklower llc_resend(struct llc_linkcb *linkp, int cmdrsp, int pollfinal)
10557027Ssklower {
10657027Ssklower 	register struct llc *frame;
10757027Ssklower 	register struct mbuf *m;
10857027Ssklower 	register int seq, slot;
10957027Ssklower 
11057027Ssklower 	if (linkp->llcl_slotsfree < linkp->llcl_window)
11157027Ssklower 		/* assert lock between nr_received & V(S) */
11257027Ssklower 		if (linkp->llcl_nr_received != linkp->llcl_vs)
11357027Ssklower 			panic("llc: V(S) != N(R) received\n");
11457027Ssklower 
11557027Ssklower 		for (slot = llc_seq2slot(linkp, linkp->llcl_vs);
11657027Ssklower 		     slot != linkp->llcl_freeslot;
11757027Ssklower 		     LLC_INC(linkp->llcl_vs),
11857027Ssklower 		     slot = llc_seq2slot(linkp, linkp->llcl_vs)) {
11957027Ssklower 			m = linkp->llcl_output_buffers[slot];
12057027Ssklower 			LLC_GETHDR(frame, m);
12157027Ssklower 			llc_rawsend(linkp, m, frame, LLCFT_INFO, linkp->llcl_vs,
12257027Ssklower 				    cmdrsp, pollfinal);
12357027Ssklower 			pollfinal = 0;
12457027Ssklower 		}
12557027Ssklower 
12657027Ssklower 	return 0;
12757027Ssklower }
12857027Ssklower 
12957027Ssklower /*
13057027Ssklower  * llc_rawsend() --- constructs an LLC frame and sends it out via the
13157027Ssklower  *                   associated interface of the link control block.
13257027Ssklower  *
13357027Ssklower  * We need to make sure that outgoing frames have the correct length,
13457027Ssklower  * in particular the 4 byte ones (RR, RNR, REJ) as LLC_GETHDR() will
13557027Ssklower  * set the mbuf len to 3 as default len for non INFO frames ...
13657027Ssklower  *
13757027Ssklower  * Frame kind             Length (w/o MAC header, {D,S}SAP incl.)
13857027Ssklower  * --------------------------------------------------------------
13957027Ssklower  * DISC, SABME, UA, DM    3 bytes  ({D,S}SAP + CONTROL)
14057027Ssklower  * RR, RNR, REJ           4 bytes  ({D,S}SAP + CONTROL0 + CONTROL1)
14157027Ssklower  * XID                    6 bytes  ({D,S}SAP + CONTROL0 + FI,CLASS,WINDOW)
14257027Ssklower  * FRMR                   7 bytes  ({D,S}SAP + CONTROL0 + REJ CONTROL,V(S),V(R),CAUSE)
14357027Ssklower  * INFO                   4 -- MTU
14457027Ssklower  * UI, TEST               3 -- MTU
14557027Ssklower  *
14657027Ssklower  */
14757027Ssklower #define LLC_SETLEN(m, l) (m)->m_pkthdr.len = (m)->m_len = (l)
14857027Ssklower 
llc_rawsend(struct llc_linkcb * linkp,struct mbuf * m,struct llc * frame,int frame_kind,int vs,int cmdrsp,int pollfinal)14957027Ssklower llc_rawsend(struct llc_linkcb *linkp, struct mbuf *m, struct llc *frame,
15057027Ssklower 	    int frame_kind, int vs, int cmdrsp, int pollfinal)
15157027Ssklower {
15257027Ssklower 	register short adjust = LLC_UFRAMELEN;
15357027Ssklower 	struct ifnet *ifp;
15457027Ssklower 
15557027Ssklower 	switch (frame_kind) {
15657027Ssklower 	/* supervisory and information frames */
15757027Ssklower 	case LLCFT_INFO:
15857027Ssklower 		frame->llc_control = LLC_INFO;
15957027Ssklower 		LLCSBITS(frame->llc_control, i_ns, vs);
16057027Ssklower 		LLCSBITS(frame->llc_control_ext, i_nr, linkp->llcl_vr);
16157027Ssklower 		adjust = LLC_ISFRAMELEN;
16257027Ssklower 		break;
16357027Ssklower 	case LLCFT_RR:
16457027Ssklower 		frame->llc_control = LLC_RR;
16557027Ssklower 		LLC_SETLEN(m, LLC_ISFRAMELEN);
16657027Ssklower 		LLCSBITS(frame->llc_control_ext, s_nr, linkp->llcl_vr);
16757027Ssklower 		adjust = LLC_ISFRAMELEN;
16857027Ssklower 		break;
16957027Ssklower 	case LLCFT_RNR:
17057027Ssklower 		frame->llc_control = LLC_RNR;
17157027Ssklower 		LLC_SETLEN(m, LLC_ISFRAMELEN);
17257027Ssklower 		LLCSBITS(frame->llc_control_ext, s_nr, linkp->llcl_vr);
17357027Ssklower 		adjust = LLC_ISFRAMELEN;
17457027Ssklower 		break;
17557027Ssklower 	case LLCFT_REJ:
17657027Ssklower 		frame->llc_control = LLC_REJ;
17757027Ssklower 		LLC_SETLEN(m, LLC_ISFRAMELEN);
17857027Ssklower 		LLCSBITS(frame->llc_control_ext, s_nr, linkp->llcl_vr);
17957027Ssklower 		adjust = LLC_ISFRAMELEN;
18057027Ssklower 		break;
18157027Ssklower 	/* unnumbered frames */
18257027Ssklower 	case LLCFT_DM:
18357027Ssklower 		frame->llc_control = LLC_DM;
18457027Ssklower 		break;
18557027Ssklower 	case LLCFT_SABME:
18657027Ssklower 		frame->llc_control = LLC_SABME;
18757027Ssklower 		break;
18857027Ssklower 	case LLCFT_DISC:
18957027Ssklower 		frame->llc_control = LLC_DISC;
19057027Ssklower 		break;
19157027Ssklower 	case LLCFT_UA:
19257027Ssklower 		frame->llc_control = LLC_UA;
19357027Ssklower 		break;
19457027Ssklower 	case LLCFT_UI:
19557027Ssklower 		frame->llc_control = LLC_UI;
19657027Ssklower 		break;
19757027Ssklower 	case LLCFT_FRMR:
19857027Ssklower 		frame->llc_control = LLC_FRMR;
19957027Ssklower 		/* get more space --- FRMR frame are longer then usual */
20057027Ssklower 		LLC_SETLEN(m, LLC_FRMRLEN);
20157027Ssklower 		bcopy((caddr_t) &linkp->llcl_frmrinfo,
20257027Ssklower 		      (caddr_t) &frame->llc_frmrinfo,
20357027Ssklower 		      sizeof(struct frmrinfo));
20457027Ssklower 		break;
20557027Ssklower 	default:
20657027Ssklower 		/*
20757027Ssklower 		 * We don't send {XID, TEST} frames
20857027Ssklower 		 */
20957027Ssklower 		if (m)
21057027Ssklower 			m_freem(m);
21157027Ssklower 		return;
21257027Ssklower 	}
21357027Ssklower 
21457027Ssklower 	/*
21557027Ssklower 	 * Fill in DSAP/SSAP
21657027Ssklower 	 */
21757027Ssklower 	frame->llc_dsap = frame->llc_ssap = LLSAPADDR(&linkp->llcl_addr);
21857027Ssklower 	frame->llc_ssap |= cmdrsp;
21957027Ssklower 
22057027Ssklower 	/*
22157027Ssklower 	 * Check for delayed action pending. ISO 8802-2, 7.9.2 (5)
22257027Ssklower 	 * and ISO 8802-2, 7.9.2.3 (32), (34), (36) pertain to this
22357027Ssklower 	 * piece of code --- hopefully we got it right here (i.e.
22457027Ssklower 	 * in the spirit of (32), (34), and (36) ...
22557027Ssklower 	 */
22657027Ssklower 	switch (frame_kind) {
22757027Ssklower 	case LLCFT_RR:
22857027Ssklower 	case LLCFT_RNR:
22957027Ssklower 	case LLCFT_REJ:
23057027Ssklower 	case LLCFT_INFO:
23157027Ssklower 		switch (LLC_GETFLAG(linkp, DACTION)) {
23257027Ssklower 		case LLC_DACKCMD:
23357027Ssklower 		case LLC_DACKRSP:
23457027Ssklower 			LLC_STOPTIMER(linkp, DACTION);
23557027Ssklower 			break;
23657027Ssklower 		case LLC_DACKCMDPOLL:
23757027Ssklower 			if (cmdrsp == LLC_CMD) {
23857027Ssklower 				pollfinal = 1;
23957027Ssklower 				LLC_STOPTIMER(linkp, DACTION);
24057027Ssklower 			}
24157027Ssklower 			break;
24257027Ssklower 		case LLC_DACKRSPFINAL:
24357027Ssklower 			if (cmdrsp == LLC_RSP) {
24457027Ssklower 				pollfinal = 1;
24557027Ssklower 				LLC_STOPTIMER(linkp, DACTION);
24657027Ssklower 			}
24757027Ssklower 			break;
24857027Ssklower 		}
24957027Ssklower 		break;
25057027Ssklower 	}
25157027Ssklower 
25257027Ssklower 	if (adjust == LLC_UFRAMELEN)
25357027Ssklower 		LLCSBITS(frame->llc_control, u_pf, pollfinal);
25457027Ssklower 	else LLCSBITS(frame->llc_control_ext, s_pf, pollfinal);
25557027Ssklower 
25657027Ssklower 	/*
25757027Ssklower 	 * Get interface to send frame onto
25857027Ssklower 	 */
25957027Ssklower 	ifp = linkp->llcl_if;
26057027Ssklower 	if (frame_kind == LLCFT_INFO) {
26157027Ssklower 		/*
26257027Ssklower 		 * send out a copy of the frame, retain the
26357027Ssklower 		 * original
26457027Ssklower 		 */
26557027Ssklower 		(*ifp->if_output)(ifp, m_copy(m, 0, (int)M_COPYALL),
26657027Ssklower 				  rt_key(linkp->llcl_nlrt),
26757027Ssklower 				  linkp->llcl_nlrt);
26857027Ssklower 		/*
26957027Ssklower 		 * Account for the LLC header and let it ``disappear''
27057027Ssklower 		 * as the raw info frame payload is what we hold in
27157027Ssklower 		 * the output_buffers of the link.
27257027Ssklower 		 */
27357027Ssklower 		m_adj(m, LLC_ISFRAMELEN);
27457027Ssklower 	} else (*ifp->if_output)(ifp, m,
27557027Ssklower 				 rt_key(linkp->llcl_nlrt),
27657027Ssklower 				 linkp->llcl_nlrt);
27757027Ssklower }
27857027Ssklower 
279