aboutsummaryrefslogtreecommitdiff
path: root/sys/netccitt/llc_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netccitt/llc_output.c')
-rw-r--r--sys/netccitt/llc_output.c304
1 files changed, 304 insertions, 0 deletions
diff --git a/sys/netccitt/llc_output.c b/sys/netccitt/llc_output.c
new file mode 100644
index 000000000000..98d0328a5f55
--- /dev/null
+++ b/sys/netccitt/llc_output.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) Dirk Husemann, Computer Science Department IV,
+ * University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Dirk Husemann and the Computer Science Department (IV) of
+ * the University of Erlangen-Nuremberg, Germany.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)llc_output.c 8.1 (Berkeley) 6/10/93
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/socket.h>
+#include <sys/protosw.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_llc.h>
+#include <net/route.h>
+
+#include <netccitt/dll.h>
+#include <netccitt/llc_var.h>
+
+/*
+ * llc_output() --- called by an upper layer (network layer) entity whenever
+ * there is an INFO frame to be transmitted. We enqueue the
+ * info frame and call llc_start() to do the actual sending.
+ */
+
+llc_output(struct llc_linkcb *linkp, struct mbuf *m)
+{
+ register int i;
+
+ i = splimp();
+ LLC_ENQUEUE(linkp, m);
+ llc_start(linkp);
+ splx(i);
+
+}
+
+
+/*
+ * llc_start() --- We try to subsequently dequeue all the frames available and
+ * send them out.
+ */
+void
+llc_start(struct llc_linkcb *linkp)
+{
+ register int i;
+ register struct mbuf *m;
+ int action;
+
+ while ((LLC_STATEEQ(linkp, NORMAL) || LLC_STATEEQ(linkp, BUSY) ||
+ LLC_STATEEQ(linkp, REJECT)) &&
+ (linkp->llcl_slotsfree > 0) &&
+ (LLC_GETFLAG(linkp, REMOTE_BUSY) == 0)) {
+ LLC_DEQUEUE(linkp, m);
+ if (m == NULL)
+ break;
+ LLC_SETFRAME(linkp, m);
+ (void)llc_statehandler(linkp, (struct llc *) 0, NL_DATA_REQUEST,
+ 0, 0);
+ }
+}
+
+
+/*
+ * llc_send() --- Handles single frames. If dealing with INFO frames we need to
+ * prepend the LLC header, otherwise we just allocate an mbuf.
+ * In both cases the actual send is done by llc_rawsend().
+ */
+llc_send(struct llc_linkcb *linkp, int frame_kind, int cmdrsp, int pollfinal)
+{
+ register struct mbuf *m = (struct mbuf *)0;
+ register struct llc *frame;
+
+ if (frame_kind == LLCFT_INFO)
+ m = linkp->llcl_output_buffers[llc_seq2slot(linkp,
+ linkp->llcl_vs)];
+ LLC_GETHDR(frame, m);
+
+ /* pass it on to llc_rawsend() */
+ llc_rawsend(linkp, m, frame, frame_kind, linkp->llcl_vs, cmdrsp, pollfinal);
+
+ if (frame_kind == LLCFT_INFO)
+ LLC_INC(linkp->llcl_vs);
+
+ return 0;
+}
+
+/*
+ * llc_resend() --- llc_resend() retransmits all unacknowledged INFO frames.
+ */
+llc_resend(struct llc_linkcb *linkp, int cmdrsp, int pollfinal)
+{
+ register struct llc *frame;
+ register struct mbuf *m;
+ register int seq, slot;
+
+ if (linkp->llcl_slotsfree < linkp->llcl_window)
+ /* assert lock between nr_received & V(S) */
+ if (linkp->llcl_nr_received != linkp->llcl_vs)
+ panic("llc: V(S) != N(R) received\n");
+
+ for (slot = llc_seq2slot(linkp, linkp->llcl_vs);
+ slot != linkp->llcl_freeslot;
+ LLC_INC(linkp->llcl_vs),
+ slot = llc_seq2slot(linkp, linkp->llcl_vs)) {
+ m = linkp->llcl_output_buffers[slot];
+ LLC_GETHDR(frame, m);
+ llc_rawsend(linkp, m, frame, LLCFT_INFO, linkp->llcl_vs,
+ cmdrsp, pollfinal);
+ pollfinal = 0;
+ }
+
+ return 0;
+}
+
+/*
+ * llc_rawsend() --- constructs an LLC frame and sends it out via the
+ * associated interface of the link control block.
+ *
+ * We need to make sure that outgoing frames have the correct length,
+ * in particular the 4 byte ones (RR, RNR, REJ) as LLC_GETHDR() will
+ * set the mbuf len to 3 as default len for non INFO frames ...
+ *
+ * Frame kind Length (w/o MAC header, {D,S}SAP incl.)
+ * --------------------------------------------------------------
+ * DISC, SABME, UA, DM 3 bytes ({D,S}SAP + CONTROL)
+ * RR, RNR, REJ 4 bytes ({D,S}SAP + CONTROL0 + CONTROL1)
+ * XID 6 bytes ({D,S}SAP + CONTROL0 + FI,CLASS,WINDOW)
+ * FRMR 7 bytes ({D,S}SAP + CONTROL0 + REJ CONTROL,V(S),V(R),CAUSE)
+ * INFO 4 -- MTU
+ * UI, TEST 3 -- MTU
+ *
+ */
+#define LLC_SETLEN(m, l) (m)->m_pkthdr.len = (m)->m_len = (l)
+
+llc_rawsend(struct llc_linkcb *linkp, struct mbuf *m, struct llc *frame,
+ int frame_kind, int vs, int cmdrsp, int pollfinal)
+{
+ register short adjust = LLC_UFRAMELEN;
+ struct ifnet *ifp;
+
+ switch (frame_kind) {
+ /* supervisory and information frames */
+ case LLCFT_INFO:
+ frame->llc_control = LLC_INFO;
+ LLCSBITS(frame->llc_control, i_ns, vs);
+ LLCSBITS(frame->llc_control_ext, i_nr, linkp->llcl_vr);
+ adjust = LLC_ISFRAMELEN;
+ break;
+ case LLCFT_RR:
+ frame->llc_control = LLC_RR;
+ LLC_SETLEN(m, LLC_ISFRAMELEN);
+ LLCSBITS(frame->llc_control_ext, s_nr, linkp->llcl_vr);
+ adjust = LLC_ISFRAMELEN;
+ break;
+ case LLCFT_RNR:
+ frame->llc_control = LLC_RNR;
+ LLC_SETLEN(m, LLC_ISFRAMELEN);
+ LLCSBITS(frame->llc_control_ext, s_nr, linkp->llcl_vr);
+ adjust = LLC_ISFRAMELEN;
+ break;
+ case LLCFT_REJ:
+ frame->llc_control = LLC_REJ;
+ LLC_SETLEN(m, LLC_ISFRAMELEN);
+ LLCSBITS(frame->llc_control_ext, s_nr, linkp->llcl_vr);
+ adjust = LLC_ISFRAMELEN;
+ break;
+ /* unnumbered frames */
+ case LLCFT_DM:
+ frame->llc_control = LLC_DM;
+ break;
+ case LLCFT_SABME:
+ frame->llc_control = LLC_SABME;
+ break;
+ case LLCFT_DISC:
+ frame->llc_control = LLC_DISC;
+ break;
+ case LLCFT_UA:
+ frame->llc_control = LLC_UA;
+ break;
+ case LLCFT_UI:
+ frame->llc_control = LLC_UI;
+ break;
+ case LLCFT_FRMR:
+ frame->llc_control = LLC_FRMR;
+ /* get more space --- FRMR frame are longer then usual */
+ LLC_SETLEN(m, LLC_FRMRLEN);
+ bcopy((caddr_t) &linkp->llcl_frmrinfo,
+ (caddr_t) &frame->llc_frmrinfo,
+ sizeof(struct frmrinfo));
+ break;
+ default:
+ /*
+ * We don't send {XID, TEST} frames
+ */
+ if (m)
+ m_freem(m);
+ return;
+ }
+
+ /*
+ * Fill in DSAP/SSAP
+ */
+ frame->llc_dsap = frame->llc_ssap = LLSAPADDR(&linkp->llcl_addr);
+ frame->llc_ssap |= cmdrsp;
+
+ /*
+ * Check for delayed action pending. ISO 8802-2, 7.9.2 (5)
+ * and ISO 8802-2, 7.9.2.3 (32), (34), (36) pertain to this
+ * piece of code --- hopefully we got it right here (i.e.
+ * in the spirit of (32), (34), and (36) ...
+ */
+ switch (frame_kind) {
+ case LLCFT_RR:
+ case LLCFT_RNR:
+ case LLCFT_REJ:
+ case LLCFT_INFO:
+ switch (LLC_GETFLAG(linkp, DACTION)) {
+ case LLC_DACKCMD:
+ case LLC_DACKRSP:
+ LLC_STOPTIMER(linkp, DACTION);
+ break;
+ case LLC_DACKCMDPOLL:
+ if (cmdrsp == LLC_CMD) {
+ pollfinal = 1;
+ LLC_STOPTIMER(linkp, DACTION);
+ }
+ break;
+ case LLC_DACKRSPFINAL:
+ if (cmdrsp == LLC_RSP) {
+ pollfinal = 1;
+ LLC_STOPTIMER(linkp, DACTION);
+ }
+ break;
+ }
+ break;
+ }
+
+ if (adjust == LLC_UFRAMELEN)
+ LLCSBITS(frame->llc_control, u_pf, pollfinal);
+ else LLCSBITS(frame->llc_control_ext, s_pf, pollfinal);
+
+ /*
+ * Get interface to send frame onto
+ */
+ ifp = linkp->llcl_if;
+ if (frame_kind == LLCFT_INFO) {
+ /*
+ * send out a copy of the frame, retain the
+ * original
+ */
+ (*ifp->if_output)(ifp, m_copy(m, 0, (int)M_COPYALL),
+ rt_key(linkp->llcl_nlrt),
+ linkp->llcl_nlrt);
+ /*
+ * Account for the LLC header and let it ``disappear''
+ * as the raw info frame payload is what we hold in
+ * the output_buffers of the link.
+ */
+ m_adj(m, LLC_ISFRAMELEN);
+ } else (*ifp->if_output)(ifp, m,
+ rt_key(linkp->llcl_nlrt),
+ linkp->llcl_nlrt);
+}
+