#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 <netccitt/hdlc.h>
#include <netccitt/hd_var.h>
#include <netccitt/x25.h>
static frame_reject();
static rej_routine();
static free_iframes();
hdintr ()
{
register struct mbuf *m;
register struct hdcb *hdp;
register struct ifnet *ifp;
register int s;
static struct ifnet *lastifp;
static struct hdcb *lasthdp;
for (;;) {
s = splimp ();
IF_DEQUEUE (&hdintrq, m);
splx (s);
if (m == 0)
break;
if (m->m_len < HDHEADERLN) {
printf ("hdintr: packet too short (len=%d)\n",
m->m_len);
m_freem (m);
continue;
}
if ((m->m_flags & M_PKTHDR) == 0)
panic("hdintr");
ifp = m->m_pkthdr.rcvif;
if (ifp == lastifp)
hdp = lasthdp;
else {
for (hdp = hdcbhead; hdp; hdp = hdp->hd_next)
if (hdp->hd_ifp == ifp)
break;
if (hdp == 0) {
printf ("hdintr: unknown interface %x\n", ifp);
m_freem (m);
continue;
}
lastifp = ifp;
lasthdp = hdp;
}
if (process_rxframe (hdp, m) == FALSE)
m_freem (m);
}
}
process_rxframe (hdp, fbuf)
register struct hdcb *hdp;
register struct mbuf *fbuf;
{
register int queued = FALSE, frametype, pf;
register struct Hdlc_frame *frame;
frame = mtod (fbuf, struct Hdlc_frame *);
pf = ((struct Hdlc_iframe *) frame) -> pf;
hd_trace (hdp, RX, frame);
if (frame -> address != ADDRESS_A && frame -> address != ADDRESS_B)
return (queued);
switch ((frametype = hd_decode (hdp, frame)) + hdp->hd_state) {
case DM + DISC_SENT:
case UA + DISC_SENT:
hdp->hd_state = DISCONNECTED;
break;
case DM + INIT:
case UA + INIT:
hd_writeinternal (hdp, SABM, POLLOFF);
hdp->hd_state = SABM_SENT;
SET_TIMER (hdp);
break;
case SABM + DM_SENT:
case SABM + WAIT_SABM:
hd_writeinternal (hdp, UA, pf);
case UA + SABM_SENT:
case UA + WAIT_UA:
KILL_TIMER (hdp);
hd_initvars (hdp);
hdp->hd_state = ABM;
hd_message (hdp, "Link level operational");
(void) pk_ctlinput (PRC_LINKUP, hdp->hd_pkp);
break;
case SABM + SABM_SENT:
hd_writeinternal (hdp, UA, pf);
break;
case SABM + ABM:
KILL_TIMER (hdp);
hd_message (hdp, "Link reset");
#ifdef HDLCDEBUG
hd_dumptrace (hdp);
#endif
hd_flush (hdp->hd_ifp);
hd_writeinternal (hdp, UA, pf);
hd_initvars (hdp);
(void) pk_ctlinput (PRC_LINKRESET, hdp->hd_pkp);
hdp->hd_resets++;
break;
case SABM + WAIT_UA:
hd_writeinternal (hdp, UA, pf);
break;
case DM + ABM:
hd_message (hdp, "DM received: link down");
#ifdef HDLCDEBUG
hd_dumptrace (hdp);
#endif
(void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp);
hd_flush (hdp->hd_ifp);
case DM + DM_SENT:
case DM + WAIT_SABM:
case DM + WAIT_UA:
hd_writeinternal (hdp, SABM, pf);
hdp->hd_state = SABM_SENT;
SET_TIMER (hdp);
break;
case DISC + INIT:
case DISC + DM_SENT:
case DISC + SABM_SENT:
hd_writeinternal (hdp, UA, pf);
hd_writeinternal (hdp, SABM, POLLOFF);
hdp->hd_state = SABM_SENT;
SET_TIMER (hdp);
break;
case DISC + WAIT_UA:
hd_writeinternal (hdp, DM, pf);
SET_TIMER (hdp);
hdp->hd_state = DM_SENT;
break;
case DISC + ABM:
hd_message (hdp, "DISC received: link down");
(void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp);
case DISC + WAIT_SABM:
hd_writeinternal (hdp, UA, pf);
hdp->hd_state = DM_SENT;
SET_TIMER (hdp);
break;
case UA + ABM:
hd_message (hdp, "UA received: link down");
(void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp);
case UA + WAIT_SABM:
hd_writeinternal (hdp, DM, pf);
hdp->hd_state = DM_SENT;
SET_TIMER (hdp);
break;
case FRMR + DM_SENT:
hd_writeinternal (hdp, SABM, pf);
hdp->hd_state = SABM_SENT;
SET_TIMER (hdp);
break;
case FRMR + WAIT_SABM:
hd_writeinternal (hdp, DM, pf);
hdp->hd_state = DM_SENT;
SET_TIMER (hdp);
break;
case FRMR + ABM:
hd_message (hdp, "FRMR received: link down");
(void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp);
#ifdef HDLCDEBUG
hd_dumptrace (hdp);
#endif
hd_flush (hdp->hd_ifp);
hd_writeinternal (hdp, SABM, pf);
hdp->hd_state = WAIT_UA;
SET_TIMER (hdp);
break;
case RR + ABM:
case RNR + ABM:
case REJ + ABM:
process_sframe (hdp, (struct Hdlc_sframe *)frame, frametype);
break;
case IFRAME + ABM:
queued = process_iframe (hdp, fbuf, (struct Hdlc_iframe *)frame);
break;
case IFRAME + SABM_SENT:
case RR + SABM_SENT:
case RNR + SABM_SENT:
case REJ + SABM_SENT:
hd_writeinternal (hdp, DM, POLLON);
hdp->hd_state = DM_SENT;
SET_TIMER (hdp);
break;
case IFRAME + WAIT_SABM:
case RR + WAIT_SABM:
case RNR + WAIT_SABM:
case REJ + WAIT_SABM:
hd_writeinternal (hdp, FRMR, POLLOFF);
SET_TIMER (hdp);
break;
case ILLEGAL + SABM_SENT:
hdp->hd_unknown++;
hd_writeinternal (hdp, DM, POLLOFF);
hdp->hd_state = DM_SENT;
SET_TIMER (hdp);
break;
case ILLEGAL + ABM:
hd_message (hdp, "Unknown frame received: link down");
(void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp);
case ILLEGAL + WAIT_SABM:
hdp->hd_unknown++;
#ifdef HDLCDEBUG
hd_dumptrace (hdp);
#endif
hd_writeinternal (hdp, FRMR, POLLOFF);
hdp->hd_state = WAIT_SABM;
SET_TIMER (hdp);
break;
}
return (queued);
}
process_iframe (hdp, fbuf, frame)
register struct hdcb *hdp;
struct mbuf *fbuf;
register struct Hdlc_iframe *frame;
{
register int nr = frame -> nr,
ns = frame -> ns,
pf = frame -> pf;
register int queued = FALSE;
if (valid_nr (hdp, nr, FALSE) == FALSE) {
frame_reject (hdp, Z, frame);
return (queued);
}
if (ns != hdp->hd_vr) {
hdp->hd_invalid_ns++;
if (pf || (hdp->hd_condition & REJ_CONDITION) == 0) {
hdp->hd_condition |= REJ_CONDITION;
hd_flush (hdp->hd_ifp);
hd_writeinternal (hdp, REJ, pf);
}
return (queued);
}
hdp->hd_condition &= ~REJ_CONDITION;
if (ns != (hdp -> hd_lasttxnr + hdp -> hd_xcp -> xc_lwsize) % MODULUS) {
hdp -> hd_vr = (hdp -> hd_vr + 1) % MODULUS;
if (pf == 1) {
hd_writeinternal (hdp, RR, POLLON);
} else
if (hdp -> hd_rrtimer == 0)
hdp->hd_rrtimer = hd_t3;
fbuf -> m_data += HDHEADERLN;
fbuf -> m_len -= HDHEADERLN;
fbuf -> m_pkthdr.len -= HDHEADERLN;
fbuf -> m_pkthdr.rcvif = (struct ifnet *)hdp -> hd_pkp;
#ifdef BSD4_3
fbuf->m_act = 0;
#else
{
register struct mbuf *m;
for (m = fbuf; m -> m_next; m = m -> m_next)
m -> m_act = (struct mbuf *) 0;
m -> m_act = (struct mbuf *) 1;
}
#endif
pk_input (fbuf);
queued = TRUE;
hd_start (hdp);
} else {
hdp->hd_invalid_ns++;
frame_reject (hdp, W, frame);
}
return (queued);
}
bool
range_check (rear, value, front)
int rear,
value,
front;
{
register bool result = FALSE;
if (front > rear)
result = (rear <= value) && (value <= front);
else
result = (rear <= value) || (value <= front);
return (result);
}
static
frame_reject (hdp, rejectcode, frame)
struct hdcb *hdp;
struct Hdlc_iframe *frame;
{
register struct Frmr_frame *frmr = &hd_frmr;
frmr -> frmr_control = ((struct Hdlc_frame *) frame) -> control;
frmr -> frmr_ns = frame -> ns;
frmr -> frmr_f1_0 = 0;
frmr -> frmr_nr = frame -> nr;
frmr -> frmr_f2_0 = 0;
frmr -> frmr_0000 = 0;
frmr -> frmr_w = frmr -> frmr_x = frmr -> frmr_y =
frmr -> frmr_z = 0;
switch (rejectcode) {
case Z:
frmr -> frmr_z = 1;
break;
case Y:
frmr -> frmr_y = 1;
break;
case X:
frmr -> frmr_x = 1;
frmr -> frmr_w = 1;
break;
case W:
frmr -> frmr_w = 1;
}
hd_writeinternal (hdp, FRMR, POLLOFF);
hdp->hd_state = WAIT_SABM;
SET_TIMER (hdp);
}
process_sframe (hdp, frame, frametype)
register struct hdcb *hdp;
register struct Hdlc_sframe *frame;
int frametype;
{
register int nr = frame -> nr, pf = frame -> pf, pollbit = 0;
if (valid_nr (hdp, nr, pf) == TRUE) {
switch (frametype) {
case RR:
hdp->hd_condition &= ~REMOTE_RNR_CONDITION;
break;
case RNR:
hdp->hd_condition |= REMOTE_RNR_CONDITION;
hdp->hd_retxcnt = 0;
break;
case REJ:
hdp->hd_condition &= ~REMOTE_RNR_CONDITION;
rej_routine (hdp, nr);
}
if (pf == 1) {
hdp->hd_retxcnt = 0;
hdp->hd_condition &= ~TIMER_RECOVERY_CONDITION;
if (frametype == RR && hdp->hd_lastrxnr == hdp->hd_vs
&& hdp->hd_timer == 0 && hdp->hd_txq.head == 0)
hd_writeinternal(hdp, RR, pf);
else
if (hdp->hd_condition & REMOTE_RNR_CONDITION) {
if (hdp->hd_vs != hdp->hd_retxqi)
hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], pollbit);
}
else
while (hdp->hd_vs != hdp->hd_retxqi)
hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], POLLOFF);
}
hd_start (hdp);
} else
frame_reject (hdp, Z, (struct Hdlc_iframe *)frame);
}
bool
valid_nr (hdp, nr, finalbit)
register struct hdcb *hdp;
register int finalbit;
{
if (hdp->hd_lastrxnr == nr)
return (TRUE);
if (range_check (hdp->hd_lastrxnr, nr, hdp->hd_vs) == FALSE) {
if ((hdp->hd_condition & TIMER_RECOVERY_CONDITION) &&
range_check (hdp->hd_vs, nr, hdp->hd_xx) == TRUE)
hdp->hd_vs = nr;
else {
hdp->hd_invalid_nr++;
return (FALSE);
}
}
KILL_TIMER (hdp);
free_iframes (hdp, &nr, finalbit);
if (nr != hdp->hd_vs)
SET_TIMER (hdp);
return (TRUE);
}
static
rej_routine (hdp, rejnr)
register struct hdcb *hdp;
register int rejnr;
{
register int anchor;
hd_flush (hdp->hd_ifp);
anchor = hdp->hd_vs;
if (hdp->hd_condition & TIMER_RECOVERY_CONDITION)
anchor = hdp->hd_xx;
anchor = (anchor - rejnr + 8) % MODULUS;
if (anchor > 0) {
KILL_TIMER (hdp);
hdp->hd_vs = rejnr;
while (hdp->hd_vs != hdp->hd_retxqi)
hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], POLLOFF);
}
hd_start (hdp);
}
static
free_iframes (hdp, nr, finalbit)
register struct hdcb *hdp;
int *nr;
register int finalbit;
{
register int i, k;
if ((hdp->hd_condition & TIMER_RECOVERY_CONDITION) && *nr == hdp->hd_xx && finalbit == 0) {
*nr = (*nr - 1 + 8) % MODULUS;
}
k = (*nr - hdp->hd_lastrxnr + 8) % MODULUS;
for (i = 0; i < k; ++i) {
m_freem (hdp->hd_retxq[hdp->hd_lastrxnr]);
hdp->hd_retxq[hdp->hd_lastrxnr] = 0;
hdp->hd_lastrxnr = (hdp->hd_lastrxnr + 1) % MODULUS;
}
}