332 lines
9.2 KiB
C
332 lines
9.2 KiB
C
/* $NetBSD: llc_output.c,v 1.6 2001/04/13 23:30:20 thorpej Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 1990, 1991, 1992
|
|
* Dirk Husemann, Computer Science Department IV,
|
|
* University of Erlangen-Nuremberg, Germany.
|
|
* 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>
|
|
|
|
#include <machine/stdarg.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.
|
|
*/
|
|
|
|
int
|
|
#if __STDC__
|
|
llc_output(struct mbuf *m, ...)
|
|
#else
|
|
llc_output(m, va_alist)
|
|
struct mbuf *m;
|
|
va_dcl
|
|
#endif
|
|
{
|
|
struct llc_linkcb *linkp;
|
|
int i = splnet();
|
|
va_list ap;
|
|
|
|
va_start(ap, m);
|
|
linkp = va_arg(ap, struct llc_linkcb *);
|
|
va_end(ap);
|
|
|
|
LLC_ENQUEUE(linkp, m);
|
|
llc_start(linkp);
|
|
splx(i);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* llc_start() --- We try to subsequently dequeue all the frames available and
|
|
* send them out.
|
|
*/
|
|
void
|
|
llc_start(linkp)
|
|
struct llc_linkcb *linkp;
|
|
{
|
|
struct mbuf *m;
|
|
|
|
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, NULL, 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().
|
|
*/
|
|
void
|
|
llc_send(linkp, frame_kind, cmdrsp, pollfinal)
|
|
struct llc_linkcb *linkp;
|
|
int frame_kind;
|
|
int cmdrsp;
|
|
int pollfinal;
|
|
{
|
|
struct mbuf *m = (struct mbuf *) 0;
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* llc_resend() --- llc_resend() retransmits all unacknowledged INFO frames.
|
|
*/
|
|
void
|
|
llc_resend(linkp, cmdrsp, pollfinal)
|
|
struct llc_linkcb *linkp;
|
|
int cmdrsp;
|
|
int pollfinal;
|
|
{
|
|
struct llc *frame;
|
|
struct mbuf *m;
|
|
int 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;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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)
|
|
|
|
void
|
|
llc_rawsend(linkp, m, frame, frame_kind, vs, cmdrsp, pollfinal)
|
|
struct llc_linkcb *linkp;
|
|
struct mbuf *m;
|
|
struct llc *frame;
|
|
int frame_kind;
|
|
int vs;
|
|
int cmdrsp;
|
|
int pollfinal;
|
|
{
|
|
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);
|
|
}
|