diff options
Diffstat (limited to 'sys/netccitt/llc_output.c')
-rw-r--r-- | sys/netccitt/llc_output.c | 304 |
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 0000000..98d0328 --- /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); +} + |