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