u-isdn/ksupport/x75lib.c

1908 lines
45 KiB
C

#include "f_module.h"
#include "primitives.h"
#include "streams.h"
#include "kernel.h"
#ifndef linux
#include <sys/var.h>
#endif
#include "x75lib.h"
#include "streamlib.h"
#include "lap.h"
#include "f_malloc.h"
#ifndef KERNEL
#include "kernel.h"
#endif
#ifdef linux
#ifdef KERNEL
#include <linux/sched.h>
#else
#define jiffies 0
#endif
#else
#define jiffies 0
#endif
/**
** X75 / X25 / Q921 support library.
**/
/*
* Warning: This code is implemented along the lines of the Q.921 specs and
* SDL/GR diagrams. As such, it's a little redundant, but much easier to
* verify. GCC 2 does pretty good optimizing work with it.
*
* NB: The code was lots terser a few hours ago, before I decided to run it
* through indent...
*/
/*
* Timeout prototypes
*/
static void x75_T1 (x75 state);
static void x75_T3 (x75 state);
static char *x75_sname[]=
{"S_free", "S_down", "S_await_up", "S_await_down", "S_up", "S_recover",};
/*
* State change.
*/
static void
x75_setstate (x75 state, x75_status status)
{
if (state->debug & 0x02)
printf ("%sx75.%d Setstate %d/%s -> %d/%s\n", KERN_DEBUG,state->debugnr, state->status, x75_sname[state->status], status, x75_sname[status]);
if(state->status != S_free) {
state->status = status;
if(state->status == S_down)
state->errors = 0;
}
}
/*
* Macros for timeouts
*/
#ifdef OLD_TIMEOUT
#define stop_T(xx,er) do { \
int _ms = splstr(); \
if(state->T##xx) { \
state->T##xx = 0; \
if(state->debug & 0x08) \
printf("%sStop%d T"#xx" %d\n",KERN_DEBUG,state->debugnr,__LINE__); \
untimeout((void *)x75_T##xx,state); \
} splx(_ms); \
(er)=0; \
} while(0)
#define start_T(xx,er) do { \
int _ms = splstr(); \
if(! state->T##xx) { \
state->T##xx = 1; \
if(state->debug & 0x08) \
printf("%sStart%d T"#xx" %d %d\n",KERN_DEBUG,state->debugnr,state->RUN_T##xx, __LINE__); \
timeout((void *)x75_T##xx,state,(state->RUN_T##xx * HZ) / 10); \
} splx(_ms); \
(er)=0; \
} while(0)
#define restart_T(xx,er) do { \
int _ms = splstr(); \
if(state->T##xx) \
untimeout((void *)x75_T##xx,state); \
state->T##xx = 1; \
if(state->debug & 0x08) \
printf("%sRestart%d T"#xx" %d %d\n",KERN_DEBUG,state->debugnr,state->RUN_T##xx, __LINE__); \
timeout((void *)x75_T##xx,state,(state->RUN_T##xx * HZ) / 10); \
splx(_ms); \
} while(0)
#else /* NEW_TIMEOUT */
#define stop_T(xx,er) do { \
int _ms = splstr(); \
if(state->T##xx) { \
state->T##xx = 0; \
if(state->debug & 0x08) \
printf("%sStop%d T"#xx" %d\n",KERN_DEBUG,state->debugnr,__LINE__); \
untimeout(state->timer_T##xx); \
} splx(_ms); \
(er)=0; \
} while(0)
#define start_T(xx,er) do { \
int _ms = splstr(); \
if(! state->T##xx) { \
state->T##xx = 1; \
if(state->debug & 0x08) \
printf("%sStart%d T"#xx" %d %d\n",KERN_DEBUG,state->debugnr,state->RUN_T##xx,__LINE__); \
state->timer_T##xx = timeout((void *)x75_T##xx,state,(state->RUN_T##xx * HZ) / 10); \
} splx(_ms); \
(er)=0; \
} while(0)
#define restart_T(xx,er) do { \
int _ms = splstr(); \
if(state->T##xx) \
untimeout(state->timer_T##xx); \
state->T##xx = 1; \
if(state->debug & 0x08) \
printf("%sRestart%d T"#xx" %d %d\n",KERN_DEBUG,state->debugnr,state->RUN_T##xx,__LINE__); \
state->timer_T##xx = timeout((void *)x75_T##xx,state,(state->RUN_T##xx * HZ) / 10); \
splx(_ms); \
(er)=0; \
} while(0)
#endif
/*
* Send indication up.
*/
#define msg_up(state,ind,add) (*state->state)(state->ref,ind,add)
/*
* Clear state machine -- connection down.
*/
static int
kill_me (x75 state, char ind)
/* Abort the connection, reset everything */
{
int err2 = 0;
int ms = splstr ();
x75_status oldstate = state->status;
S_flush (&state->I);
S_flush (&state->UI);
x75_setstate(state, S_down);
stop_T (1, err2);
stop_T (3, err2);
if (ind != 0 && oldstate != S_free && oldstate != S_down)
msg_up (state, ind, 0);
splx (ms);
return 0;
}
/*
* Clear exception conditions.
*/
static int
clr_except (x75 state)
{
state->RNR = 0;
state->sentRR = 1;
state->inREJ = 0;
state->ack_pend = 0;
return 0;
}
/*
* Flush I queue.
*/
static int
flush_I (x75 state)
{
S_flush (&state->I);
state->v_r = state->v_s = state->v_a = 0;
if(state->backenable)
(*state->backenable) (state->ref);
return 0;
}
/*
* Start retransmission.
*/
static int
retransmit (x75 state)
{
#if 0
if (state->flush != NULL && state->v_s != state->v_a)
(*state->flush) (state->ref);
#endif
state->v_s = state->v_a;
return 0;
}
/*
* Send 3-byte header. Actually enqueue only one byte -- the caller is
* responsible for attaching the address bytes. However, we preallocate them in
* order to go easy on allocb().
*/
static int
xmit3 (x75 state, char cmd, uchar_t what)
{
mblk_t *mb;
int err;
if (state->debug & 0x80)
printf ("%sX%d%c%x ", KERN_DEBUG,state->debugnr, cmd ? 'c' : 'r', what);
mb = allocb (state->offset + 1, BPRI_HI);
if (mb == NULL) {
if(state->debug & 0x01)
printf("%sNX4 NoMem ",KERN_WARNING);
return -ENOENT;
}
mb->b_rptr += state->offset;
mb->b_wptr += state->offset;
*mb->b_wptr++ = what;
if ((err = (*state->send) (state->ref, cmd, mb)) != 0)
freemsg (mb);
return err;
}
/*
* Send 4-byte header. Actually enqueue only two bytes -- the caller is
* responsible for attaching the address bytes.
*/
static int
xmit4 (x75 state, char cmd, uchar_t what1, uchar_t what2)
{
mblk_t *mb;
int err;
if (state->debug & 0x80)
printf ("%sX%d%c%x.%x ", KERN_DEBUG,state->debugnr, cmd ? 'c' : 'r', what1, what2);
mb = allocb (state->offset + 2, BPRI_HI);
if (mb == NULL) {
if(state->debug & 0x01)
printf("%sNX4 NoMem ",KERN_WARNING);
return -ENOENT;
}
mb->b_rptr += state->offset;
mb->b_wptr += state->offset;
*mb->b_wptr++ = what1;
*mb->b_wptr++ = what2;
if ((err = (*state->send) (state->ref, cmd, mb)) != 0)
freemsg (mb);
return err;
}
#define establish(s) Xestablish(s,__LINE__)
/*
* Connection established.
*/
static int
Xestablish (x75 state, int line)
{
int err, err2;
if (state->debug & 0x10)
printf ("%sEstablish%d %d\n", KERN_EMERG,state->debugnr, line);
if(state->broadcast) {
return -ENXIO;
}
err = clr_except (state);
state->RC = 0;
x75_setstate(state, S_await_up);
if((state->errors += 10) >= 100) {
x75_setstate(state, S_down);
printf("%sERR_G 1, %d\n",KERN_INFO,state->errors);
state->errors = 0;
msg_up (state, MDL_ERROR_IND, ERR_G);
msg_up (state, DL_RELEASE_IND, 0);
x75_setstate(state, S_down);
return -ETIMEDOUT;
}
#if 0
if(!state->wide) { int i; printf("Xestablish %d\n",jiffies);
for (i=0;i<64;i++) {
printf("%08x ",*(i-1+(unsigned long *)&state));
if(!((i+1) & 0x03))
printf("\n");
}
}
#endif
err2 = xmit3 (state, 1, (state->wide ? L2_SABME : L2_SABM) | L2_PF_U);
if (err == 0)
err = err2;
restart_T (1, err2);
if (err == 0)
err = err2;
stop_T (3, err2);
if (err == 0)
err = err2;
return err;
}
#define recover_NR(s) Xrecover_NR(s,__LINE__)
/*
* Reestablish the connection due to lost N_R synchronisation.
*/
static int
Xrecover_NR (x75 state, int line)
{
int err;
if (state->flush != NULL)
(*state->flush) (state->ref);
printf("%sERR_J 1\n",KERN_INFO);
msg_up (state, MDL_ERROR_IND, ERR_J);
err = Xestablish (state, line);
state->L3_req = 0;
return err;
}
/*
* Force sending an enquiry packet (P bit set)
*/
static int
enquiry (x75 state)
{
int err, err2;
if (state->wide)
err = xmit4 (state, 1, ((state->sentRR = (state->canrecv == NULL || (*state->canrecv) (state->ref))) ? L2_RR : L2_RNR), (state->v_r << 1) | L2_PF_S);
else
err = xmit3 (state, 1, ((state->sentRR = (state->canrecv == NULL || (*state->canrecv) (state->ref))) ? L2_RR : L2_RNR) | (state->v_r << 5) | L2_PF);
if(err == 0)
state->ack_pend = 0;
start_T (1, err2);
if (err == 0)
err = err2;
return err;
}
/*
* Respond to an enquiry packet (F bit set)
*/
static int
enq_resp (x75 state)
{
int err;
if (state->wide)
err = xmit4 (state, 0, ((state->sentRR = (state->canrecv == NULL || (*state->canrecv) (state->ref))) ? L2_RR : L2_RNR), (state->v_r << 1) | L2_PF_S);
else
err = xmit3 (state, 0, ((state->sentRR = (state->canrecv == NULL || (*state->canrecv) (state->ref))) ? L2_RR : L2_RNR) | (state->v_r << 5) | L2_PF);
if(err == 0)
state->ack_pend = 0;
return err;
}
/*
* T1 (T201) resends packets because no ack has arrived for them.
*/
static void
x75_T1 (x75 state)
{
int err2 = 0;
state->T1 = 0;
if (state->debug & 0x10)
printf ("%sT%d.1 %d RC %d\n", KERN_DEBUG,state->debugnr, state->status, state->RC);
switch (state->status) {
case S_await_up:
if (state->RC != 0) { /* temporary kludge */
if (state->RC < state->N1) {
state->RC++;
if(!state->wide) {
#ifdef linux
printf("%sXtimeout %ld\n",KERN_DEBUG,jiffies);
#endif
#if 0
{
int i;
for (i=0;i<64;i++) {
printf("%08x ", *(i-1+(unsigned long *)&state));
if(!((i+1) & 0x03))
printf("\n");
}
}
#endif
}
err2 = xmit3 (state, 1, (state->wide ? L2_SABME : L2_SABM) | L2_PF_U);
if (err2 == -EAGAIN)
state->RC--;
start_T (1, err2);
} else {
flush_I (state);
printf("%sERR_G 2, %d\n",KERN_INFO,state->N1);
msg_up (state, MDL_ERROR_IND, ERR_G);
msg_up (state, DL_RELEASE_IND, 0);
x75_setstate(state, S_down);
}
} else {
state->RC = 1;
start_T (1, err2);
break;
}
break;
case S_up:
/*
* Implementation decision time. Retransmit the last frame? We choose
* not to because we are unable to clear the xmit queue.
*/
state->RC = 1;
enquiry (state);
start_T (1, err2);
x75_setstate(state, S_recover);
break;
case S_await_down:
if (state->RC < state->N1) {
state->RC++;
xmit3 (state, 1, L2_DISC | L2_PF_U);
start_T (1, err2);
} else {
printf("%sERR_H 1\n",KERN_INFO);
msg_up (state, MDL_ERROR_IND, ERR_H);
msg_up (state, DL_RELEASE_CONF, 0);
x75_setstate(state, S_down);
}
break;
case S_recover:
if (state->RC < state->N1) {
enquiry (state);
state->RC++;
start_T (1, err2);
} else {
printf("%sERR_I 1 %d\n",KERN_INFO,state->RC);
msg_up (state, MDL_ERROR_IND, ERR_I);
establish (state);
state->L3_req = 0;
}
break;
default:;
}
x75_check_pending (state, 0);
return;
}
/*
* T3/T203 periodically sends an enquiry to make sure that the connection is
* still alive.
*/
static void
x75_T3 (x75 state)
{
state->T3 = 0;
if (state->debug & 0x10)
printf ("%sT%d.3 %d\n", KERN_DEBUG,state->debugnr, state->status);
switch (state->status) {
case S_up:
x75_setstate(state, S_recover);
(void) enquiry (state); /* Errors are handled by retransmission
* through T1 */
state->RC = 0;
break;
default:;
}
return;
}
/*
* "OOPS" time. The other side sent a bad frame.
*
* There are some differences between X.25, X.75 and Q.921 in this area,
* but given a conforming implementation on the other side this code
* should not be executed anyway. (Yeah, right...)
*/
static int
send_FRMR (x75 state, uchar_t pf, uchar_t cntl1, uchar_t cntl2, uchar_t cmd, uchar_t w, uchar_t x, uchar_t y, uchar_t z)
{
int err = 0;
mblk_t *mb = allocb (state->offset + (state->wide ? 6 : 4), BPRI_HI);
if (mb == NULL)
return -ENOMEM;
mb->b_rptr += state->offset;
mb->b_wptr += state->offset;
*mb->b_wptr++ = L2_FRMR | (pf ? L2_PF : 0);
*mb->b_wptr++ = cntl1;
if (state->wide) {
*mb->b_wptr++ = cntl2;
*mb->b_wptr++ = state->v_s << 1;
*mb->b_wptr++ = (state->v_r << 1) | (cmd ? 1 : 0);
} else {
*mb->b_wptr++ = (state->v_r << 5) | (cmd ? 0x10 : 0) | (state->v_s << 1);
}
*mb->b_wptr++ = (w ? 1 : 0) | (x ? 2 : 0) | (y ? 4 : 0) | (z ? 8 : 0);
if ((err = (*state->send) (state->ref, 0, mb)) != 0)
freemsg (mb);
return err;
}
/*
* Send pending frames.
*/
#ifdef CONFIG_DEBUG_ISDN
int
deb_x75_check_pending (const char *deb_file, unsigned int deb_line, x75 state, char fromLow)
#else
int
x75_check_pending (x75 state, char fromLow)
#endif
{
mblk_t *mb, *mb2;
char did = 0;
int k_now;
int err = 0, err2;
#if 0 /* def CONFIG_DEBUG_ISDN */
if(state->debug & 1)
printf("%sCP%d %s:%d ",KERN_DEBUG,state->debugnr,deb_file,deb_line);
#ifdef CONFIG_DEBUG_STREAMS
cS_check(deb_file,deb_line,&state->UI,NULL);
#endif
#else
if(state->debug & 1)
printf("%sCP%d ",KERN_DEBUG,state->debugnr);
#endif
if(state->status == S_free)
return -ENXIO;
while (state->UI.first != NULL && (state->cansend == NULL || (*state->cansend) (state->ref))) {
mb2 = S_dequeue (&state->UI);
if(mb2 == NULL)
break;
if( /* XXX */ 0 || DATA_REFS(mb2) > 1 || DATA_START(mb2) > mb2->b_rptr - 1) {
mb = allocb (state->offset + 1, BPRI_MED);
if (mb == NULL)
break;
mb->b_rptr += state->offset + 1;
mb->b_wptr += state->offset + 1;
linkb (mb, mb2);
} else
mb = mb2;
*--mb->b_rptr = L2_UI;
if (state->debug & 1)
printf ("%sX%dc%x ", KERN_DEBUG,state->debugnr, mb->b_wptr[-1] & 0xFF);
if ((err = (*state->send) (state->ref, state->asBroadcast ? 3 : 1, mb)) != 0) {
if (err == -EAGAIN) { /* Undo the above */
mb->b_rptr++;
mb = pullupm(mb,1);
S_requeue (&state->UI, mb);
} else
freemsg (mb);
return 0;
} else
did ++;
}
/*
* If no connection established, bail out now. If recovering, don't try to
* send pending I frames because we're still waiting for an ack.
*/
if (state->status != S_up) {
if((state->I.first != NULL) && state->debug)
printf("%sx75.%d: State %d/%s, pending\n",KERN_DEBUG,state->debugnr,state->status,x75_sname[state->status]);
if ((state->status == S_await_up) && fromLow) {
stop_T(1,err);
x75_T1(state);
}
if (state->status != S_recover) {
if(did && state->backenable)
(*state->backenable) (state->ref);
return -EAGAIN;
}
} else {
did=0;
/*
* Send frames until queue full or max # of outstanding frames reached.
*/
k_now = (state->v_s - state->v_a) & (state->wide ? 0x7F : 0x07);
/* k_now: Number of sent but unack'd frames. */
while (k_now < state->k && !state->RNR && (state->cansend == NULL || (*state->cansend) (state->ref))) {
mb2 = S_nr (&state->I, k_now);
if (mb2 == NULL) /* No more work in queue */
break;
if( /* XXX */ 0 || DATA_REFS(mb2) > 2 || DATA_START(mb2) > mb2->b_rptr - (state->wide ? 2 : 1)) {
int off = state->offset + (state->wide ? 2 : 1);
mb = allocb (off, BPRI_HI);
if (mb == NULL)
break;
mb->b_rptr += off;
mb->b_wptr += off;
linkb(mb,mb2);
} else {
mb = mb2;
}
if (state->wide) {
*--mb->b_rptr = state->v_r << 1;
*--mb->b_rptr = state->v_s << 1;
if (state->debug & 1)
printf ("%sX%dc%x.%x ", KERN_DEBUG,state->debugnr, mb->b_rptr[0] & 0xFF, mb->b_rptr[1] & 0xFF);
} else {
*--mb->b_rptr = (state->v_s << 1) | (state->v_r << 5);
if (state->debug & 1)
printf ("%sX%dc%x ", KERN_DEBUG,state->debugnr, mb->b_rptr[0] & 0xFF);
}
state->v_s = (state->v_s + 1) & (state->wide ? 0x7F : 0x07);
if ((err = (*state->send) (state->ref, 1, mb)) != 0) {
freemsg (mb);
break;
}
k_now++;
did++;
}
/* Start T1 if we're now waiting for an ack. */
if (did && !state->T1) {
stop_T (3, err);
start_T (1, err);
}
}
/*
* Send an ack packet if we didn't do it implicitly with a data frame,
* above.
*
* TODO: Delay the ack if we can determine that an immediate ack is
* not needed, i.e. if the line delay is lower than (k-1) times the
* average(?) frame length.
*/
if (!state->sentRR) {
if (state->canrecv == NULL || (*state->canrecv) (state->ref)) {
state->sentRR = 1;
did = 0;
state->ack_pend = 1; /* Send RR now. This makes sure the if statement, below, fires. */
}
} else {
if (state->canrecv != NULL && !(*state->canrecv) (state->ref))
state->sentRR = 0;
}
if (!did && state->ack_pend) {
if (state->wide)
err2 = xmit4 (state, 0, (state->sentRR ? L2_RR : L2_RNR), state->v_r << 1);
else
err2 = xmit3 (state, 0, (state->sentRR ? L2_RR : L2_RNR) | (state->v_r << 5));
if(err2 == 0)
state->ack_pend = 0;
if (err == 0)
err = err2;
}
#if 0 /* def CONFIG_DEBUG_ISDN */
else if(did) printf("%sNX send ",KERN_DEBUG );
else printf("%sNX NoAckPend ",KERN_DEBUG );
#endif
/*
* Ugly Hack time. Continuously ask the remote side what's going on while
* it is on RNR. This is for the benefit of partners who forget to send RR
* when they can accept data again.
*/
if (state->RNR && state->poll && state->trypoll) {
if (state->wide)
err2 = xmit4 (state, 1, (state->sentRR ? L2_RR : L2_RNR), state->v_r << 1 | L2_PF_S);
else
err2 = xmit3 (state, 1, (state->sentRR ? L2_RR : L2_RNR) | (state->v_r << 5) | L2_PF);
if(err2 == 0) state->ack_pend = 0;
if (err == 0)
err = err2;
}
if (state->trypoll)
state->trypoll = 0;
return err;
}
/*
* Check if the received N_R is reasonable, i.e. between v_a and v_s.
*/
static int
checkV (x75 state, uchar_t n_r)
{
if ((n_r == state->v_a) && (n_r == state->v_s))
return 1;
if (state->debug & 0x08)
printf ("%sChk%d %d <= %d <= %d\n",KERN_DEBUG,state->debugnr, state->v_a, n_r, state->v_s);
if (state->v_a <= state->v_s) {
if (state->v_a <= n_r && n_r <= state->v_s)
return 1;
} else {
if (state->v_a <= n_r || n_r <= state->v_s)
return 1;
}
printf ("\n%s*** X75-%d Sequence error: V_A %d, N_R %d, V_S %d\n",KERN_WARNING,
state->debugnr, state->v_a, n_r, state->v_s);
return 0;
}
/*
* Deallocate acknowledged frames.
*/
static int
pull_up (x75 state, uchar_t n_r)
{
int ms;
char didsome = (state->v_a != n_r);
if (!didsome)
return 0;
ms = splstr ();
while (state->v_a != n_r && state->v_a != state->v_s &&
state->I.first != NULL) {
freemsg (S_dequeue (&state->I));
if(state->errors > 0)
--state->errors;
state->v_a = (state->v_a + 1) & (state->wide ? 0x7F : 0x07);
}
if (state->v_a != n_r) {
printf ("%sx75.%d consistency problem: v_a %d, n_r %d, v_s %d, nblk %d, firstblk %p\n",KERN_WARNING,
state->debugnr, state->v_a, n_r, state->v_s, state->I.nblocks, state->I.first);
splx (ms);
return -EFAULT;
}
splx (ms);
if (didsome && state->backenable)
(*state->backenable) (state->ref);
return 0;
}
/*
* Process incoming frames.
*
* This one's a biggie. Annex B of Q.921 is very helpful if you try to wade
* through it all. Turning optimization on (having a compiler with a correct
* optimizer may be necessary...) is a good way to make sure that the kernel
* likes this code.
*
* This code went through GNU indent, which unfortunately doubled its
* line count... Sometimes, life sucks. ;-)
*/
int
x75_recv (x75 state, char cmd, mblk_t * mb)
{
uchar_t x1, x2 = 0;
char pf = 0;
int err = 0, err2;
char isbroadcast = (cmd & 2);
cmd &= 1;
/*
* Currently, this code never returns anything other than zero because it
* always deallocates the incoming frame, which is because we always mess
* around with it. This may or may not be a good idea. I don't like special
* code for the first two or three bytes being continuous. Besides, in most
* cases the caller deallocates anyway if there is an error.
*/
if((mb = pullupm (mb, 0)) == NULL)
return 0;
x1 = *mb->b_rptr++;
if (state->debug & 0x80) {
if (state->wide) {
if ((x1 & L2_m_SU) == L2_is_U) {
printf ("%sR%d%c%x ",KERN_DEBUG, state->debugnr, cmd ? 'c' : 'r', x1);
} else {
if (mb != NULL)
printf ("%sR%d%c%x.%x ", KERN_DEBUG,state->debugnr, cmd ? 'c' : 'r', x1, *mb->b_rptr & 0xFF);
else
printf ("%sR%d.half %x ",KERN_DEBUG, state->debugnr, x1);
}
} else {
printf ("%sR%d%c%x ",KERN_DEBUG, state->debugnr, cmd ? 'c' : 'r', x1);
}
}
mb = pullupm(mb,0);
if ((x1 & L2_m_I) == L2_is_I) { /* I frame */
uchar_t n_r, n_s;
if (isbroadcast) { /* Can't broadcast I frames! */
if (mb != NULL)
freemsg (mb);
return /* EINVAL */ 0;
}
/* Extract N_R, N_S, P/F. */
if (state->wide) {
if (mb == NULL) { /* "I frame" without N_R. Not good. */
err2 = send_FRMR (state, pf, x1, x2, cmd, 1, 1, 0, 0);
if (err == 0)
err = err2;
return /* err */ 0;
}
x2 = *mb->b_rptr++;
mb = pullupm (mb, 0);
pf = x2 & L2_PF_I;
n_s = (x1 >> 1) & 0x7F;
n_r = (x2 >> 1) & 0x7F;
} else {
pf = x1 & L2_PF;
x2 = 0;
n_s = (x1 >> 1) & 0x07;
n_r = (x1 >> 5) & 0x07;
}
if (!cmd || mb == NULL) {
err2 = send_FRMR (state, pf, x1, x2, cmd, 1, 1, 0, 0);
if (err == 0)
err = err2;
if (!cmd) { /* we shall process empty I frames. */
if (mb)
freemsg (mb);
return /* err */ 0;
}
}
switch (state->status) {
case S_up:
if ((state->sentRR = (state->canrecv == NULL || (*state->canrecv) (state->ref)))) {
/* Room for the packet upstreams? */
if (mb != NULL && n_s == state->v_r) {
if ((err2 = (*state->recv) (state->ref, 0, mb)) != 0) {
/* Hmmm... Assume I'm not ready after all. */
if (err == 0)
err = err2;
goto dropit; /* This is ugly, but easiest. */
} else {
state->v_r = (state->v_r + 1) & (state->wide ? 0x7f : 0x07);
if(state->errors > 0)
--state->errors;
mb = NULL;/* Accepted, so forget about it here. */
}
state->inREJ = 0;
if (pf) { /* Want immediate Ack. */
if (state->wide)
err2 = xmit4 (state, 0, L2_RR, (state->v_r << 1) | L2_PF_S);
else
err2 = xmit3 (state, 0, L2_RR | (state->v_r << 5) | L2_PF);
if(err2 == 0)
state->ack_pend = 0;
if (err == 0)
err = err2;
} else { /* Remember that we have to ack this. */
state->ack_pend = 1;
}
} else { /* Duplicate or early packet? Tell the other
* side to resync. */
if (mb != NULL) {
freemsg (mb);
mb = NULL;
}
if (state->inREJ) { /* Don't send more than one REJ; that
* would upset the protocol. */
if (pf) {
if (state->wide)
err2 = xmit4 (state, 0, L2_RR, (state->v_r << 1) | L2_PF_S);
else
err2 = xmit3 (state, 0, L2_RR | (state->v_r << 5) | L2_PF);
if(err2 == 0)
state->ack_pend = 0;
if (err == 0)
err = err2;
}
} else { /* Send REJ. */
state->inREJ = 1;
if (state->wide)
err2 = xmit4 (state, 0, L2_REJ, (state->v_r << 1) | (pf ? L2_PF_S : 0));
else
err2 = xmit3 (state, 0, L2_REJ | (state->v_r << 5) | (pf ? L2_PF : 0));
if(err2 == 0)
state->ack_pend = 0;
if (err == 0)
err = err2;
}
}
} else { /* Packet not acceptable. Tell them that we
* are busy (or something). */
dropit:
freemsg (mb);
mb = NULL;
if (pf) {
if (state->wide)
err2 = xmit4 (state, 0, L2_RNR, (state->v_r << 1) | L2_PF_S);
else
err2 = xmit3 (state, 0, L2_RNR | (state->v_r << 5) | L2_PF);
if(err2 == 0)
state->ack_pend = 0;
if (err == 0)
err = err2;
}
}
if (checkV (state, n_r)) { /* Packet in range */
if (state->RNR) { /* other side not ready */
err2 = pull_up (state, n_r);
if (err == 0)
err = err2;
} else {
if (n_r == state->v_s) { /* Everything ack'd */
err2 = pull_up (state, n_r);
if (err == 0)
err = err2;
stop_T (1, err2);
if (err == 0)
err = err2;
restart_T (3, err2);
if (err == 0)
err = err2;
} else {
if (n_r != state->v_a) { /* Something ack'd */
err2 = pull_up (state, n_r);
if (err == 0)
err = err2;
restart_T (1, err2);
if (err == 0)
err = err2;
}
/* Else if nothing ack'd, do nothing. */
}
}
} else { /* Uh oh. The packet is either totally out of
* it, or packets got reordered. Both cases
* are seriously bad. */
err2 = recover_NR (state);
if (err == 0)
err = err2;
}
break;
default:;
}
/* I frames in other states get dropped */
} else if ((x1 & L2_m_SU) == L2_is_S) { /* S frame */
uchar_t n_r;
uchar_t code;
if (isbroadcast) { /* No broadcast S frames allowed either. */
if (mb != NULL)
freemsg (mb);
return /* EINVAL */ 0;
}
if (state->wide) { /* "I frame" without N_R. Not good. */
if (mb == NULL) {
err2 = send_FRMR (state, pf, x1, x2, cmd, 1, 1, 0, 0);
if (err == 0)
err = err2;
return /* err */ 0;
}
x2 = *mb->b_rptr++;
n_r = (x2 >> 1) & 0x7F;
code = x1;
pf = x2 & L2_PF_S;
} else {
x2 = 0;
n_r = (x1 >> 5) & 0x07;
code = x1 & 0x0F;
pf = x1 & L2_PF;
}
mb = pullupm (mb, 0);
if (mb != NULL) { /* An S Frame with data field? Huh?? */
err2 = send_FRMR (state, pf, x1, x2, cmd, 1, 1, 0, 0);
if (err == 0)
err = err2;
freemsg (mb);
return /* err */ 0;
}
switch (code) {
case L2_RR:
state->trypoll = 0;
switch (state->status) {
case S_up:
if (cmd) {
if (pf) {
err2 = enq_resp (state);
if (err == 0)
err = err2;
}
} else {
if (pf) { /* This should only happen while in the
* S_recover state ... or when doing the
* force-poll-while-RNR hack. Yes it _is_
* ugly. I know that. */
if (!(state->RNR && state->poll)) {
printf("%sERR_A 1, RNR %d poll %d\n",KERN_INFO,state->RNR,state->poll);
err2 = msg_up (state, MDL_ERROR_IND, ERR_A);
if (err == 0)
err = err2;
}
}
}
state->RNR = 0;
if (checkV (state, n_r)) {
if (n_r == state->v_s) {
err2 = pull_up (state, n_r);
if (err == 0)
err = err2;
stop_T (1, err2);
if (err == 0)
err = err2;
restart_T (3, err2);
if (err == 0)
err = err2;
} else {
if (n_r != state->v_a) {
err2 = pull_up (state, n_r);
if (err == 0)
err = err2;
restart_T (1, err2);
if (err == 0)
err = err2;
}
}
} else {
err2 = recover_NR (state);
if (err == 0)
err = err2;
}
break;
case S_recover:
state->RNR = 0;
if (cmd) {
if (pf) {
err2 = enq_resp (state);
if (err == 0)
err = err2;
}
if (checkV (state, n_r)) {
err2 = pull_up (state, n_r);
if (err == 0)
err = err2;
} else {
err2 = recover_NR (state);
if (err == 0)
err = err2;
}
} else {
if (pf) {
if (checkV (state, n_r)) {
err2 = pull_up (state, n_r);
if (err == 0)
err = err2;
stop_T (1, err2);
if (err == 0)
err = err2;
start_T (3, err2);
if (err == 0)
err = err2;
err2 = retransmit (state);
if (err == 0)
err = err2;
x75_setstate(state, S_up);
} else {
err2 = recover_NR (state);
if (err == 0)
err = err2;
}
} else {
if (checkV (state, n_r)) {
err2 = pull_up (state, n_r);
if (err == 0)
err = err2;
} else {
err2 = recover_NR (state);
if (err == 0)
err = err2;
}
}
}
break;
default:;
}
break;
case L2_RNR:
state->trypoll = !pf;
switch (state->status) {
case S_up:
if (cmd) {
if (pf) {
err2 = enq_resp (state);
if (err == 0)
err = err2;
}
} else {
if (pf) {
if (!(state->poll && state->RNR)) {
printf("%sERR_A 2\n",KERN_INFO );
err2 = msg_up (state, MDL_ERROR_IND, ERR_A);
if (err == 0)
err = err2;
}
}
}
state->RNR = 1;
if (checkV (state, n_r)) {
err2 = pull_up (state, n_r);
if (err == 0)
err = err2;
stop_T (1, err2);
if (err == 0)
err = err2;
restart_T (3, err2);
if (err == 0)
err = err2;
} else {
err2 = recover_NR (state);
if (err == 0)
err = err2;
}
break;
case S_recover:
state->RNR = 1;
if (cmd) {
if (pf) {
err2 = enq_resp (state);
if (err == 0)
err = err2;
}
if (checkV (state, n_r)) {
err2 = pull_up (state, n_r);
if (err == 0)
err = err2;
} else {
err2 = recover_NR (state);
if (err == 0)
err = err2;
}
} else {
if (pf) {
if (checkV (state, n_r)) {
err2 = pull_up (state, n_r);
if (err == 0)
err = err2;
stop_T (1, err2);
if (err == 0)
err = err2;
start_T (3, err2);
if (err == 0)
err = err2;
err2 = retransmit (state);
if (err == 0)
err = err2;
x75_setstate(state, S_up);
} else {
err2 = recover_NR (state);
if (err == 0)
err = err2;
}
} else {
if (checkV (state, n_r)) {
err2 = pull_up (state, n_r);
if (err == 0)
err = err2;
} else {
err2 = recover_NR (state);
if (err == 0)
err = err2;
}
}
}
break;
default:;
}
break;
case L2_REJ:
state->trypoll = 0;
switch (state->status) {
case S_up:
if (cmd) {
if (pf) {
err2 = enq_resp (state);
if (err == 0)
err = err2;
}
} else {
if (pf) {
if (!(state->poll && state->RNR)) {
printf("%sERR_A 3\n",KERN_INFO );
err2 = msg_up (state, MDL_ERROR_IND, ERR_A);
if (err == 0)
err = err2;
}
}
}
state->RNR = 0;
if (checkV (state, n_r)) {
err2 = pull_up (state, n_r);
if (err == 0)
err = err2;
stop_T (1, err2);
if (err == 0)
err = err2;
start_T (3, err2);
if (err == 0)
err = err2;
err2 = retransmit (state);
if (err == 0)
err = err2;
} else {
err2 = recover_NR (state);
if (err == 0)
err = err2;
}
break;
case S_recover:
state->RNR = 0;
if (cmd) {
if (pf) {
err2 = enq_resp (state);
if (err == 0)
err = err2;
}
if (checkV (state, n_r)) {
err2 = pull_up (state, n_r);
if (err == 0)
err = err2;
} else {
err2 = recover_NR (state);
if (err == 0)
err = err2;
}
} else {
if (pf) {
if (checkV (state, n_r)) {
err2 = pull_up (state, n_r);
if (err == 0)
err = err2;
stop_T (1, err2);
if (err == 0)
err = err2;
start_T (3, err2);
if (err == 0)
err = err2;
err2 = retransmit (state);
if (err == 0)
err = err2;
x75_setstate(state, S_up);
} else {
err2 = recover_NR (state);
if (err == 0)
err = err2;
}
} else {
if (checkV (state, n_r)) {
err2 = pull_up (state, n_r);
if (err == 0)
err = err2;
} else {
err2 = recover_NR (state);
if (err == 0)
err = err2;
}
}
}
break;
default:;
}
break;
default:
err2 = send_FRMR (state, pf, x1, x2, cmd, 1, 0, 0, 0);
if (err == 0)
err = err2;
printf("%sERR_L 1\n",KERN_INFO);
err2 = msg_up (state, MDL_ERROR_IND, ERR_L);
if (err == 0)
err = err2;
break;
}
} else { /* U frame */
uchar_t code;
if (state->wide) {
pf = (x1 & L2_PF_U);
code = x1 & ~L2_PF_U;
} else {
pf = (x1 & L2_PF);
code = x1 & ~L2_PF;
}
if (isbroadcast && (code != L2_UI || !cmd)) {
if (mb != NULL)
freemsg (mb);
return /* EINVAL */ 0;
}
#define L2__CMD 0x100 /* Out of range -- makes for a simpler case
* statement */
switch (code | (cmd ? L2__CMD : 0)) {
case L2_SABME | L2__CMD:
case L2_SABM | L2__CMD:
if (mb != NULL) {
err2 = send_FRMR (state, pf, x1, 0, cmd, 1, 1, 0, 0);
if (err == 0)
err = err2;
printf("%sERR_N 1\n",KERN_INFO );
err2 = msg_up (state, MDL_ERROR_IND, ERR_N);
if (err == 0)
err = err2;
break;
}
if ((code == L2_SABME) != (state->wide != 0)) {
/* Configured extended mode, got normal mode, or vice versa */
printf("%sERR_? 1\n", KERN_INFO );
err2 = send_FRMR (state, pf, x1, 0, cmd, 1, 0, 0, 0);
if (err == 0)
err = err2;
break;
}
switch (state->status) {
case S_down:
if(state->broadcast) {
err2 = xmit3 (state, 0, L2_DM | (pf ? L2_PF : 0));
if (err == 0)
err = err2;
err2 = clr_except (state);
if (err == 0)
err = err2;
} else {
err2 = xmit3 (state, 0, L2_UA | (pf ? L2_PF : 0));
if (err == 0)
err = err2;
err2 = clr_except (state);
if (err == 0)
err = err2;
err2 = msg_up (state, DL_ESTABLISH_IND, 0);
if (err == 0)
err = err2;
err2 = flush_I (state);
if (err == 0)
err = err2;
stop_T (1, err2);
if (err == 0)
err = err2;
start_T (3, err2);
if (err == 0)
err = err2;
x75_setstate(state, S_up);
if(state->backenable)
(*state->backenable) (state->ref);
}
break;
case S_await_up:
err2 = xmit3 (state, 0, L2_UA | (pf ? L2_PF : 0));
if (err == 0)
err = err2;
break;
case S_await_down:
err2 = xmit3 (state, 0, L2_DM | (pf ? L2_PF : 0));
if (err == 0)
err = err2;
break;
case S_up:
case S_recover:
err2 = xmit3 (state, 0, L2_UA | (pf ? L2_PF : 0));
if (err == 0)
err = err2;
err2 = clr_except (state);
if (err == 0)
err = err2;
printf("%sERR_F 1\n",KERN_INFO );
err2 = msg_up (state, MDL_ERROR_IND, ERR_F);
if (err == 0)
err = err2;
if (state->v_s != state->v_a) {
err2 = flush_I (state);
if (err == 0)
err = err2;
err2 = msg_up (state, DL_ESTABLISH_IND, 0);
if (err == 0)
err = err2;
} else {
err2 = flush_I (state);
if (err == 0)
err = err2;
}
stop_T (1, err2);
if (err == 0)
err = err2;
start_T (3, err2);
if (err == 0)
err = err2;
x75_setstate(state, S_up);
break;
case S_free:;
}
break;
case L2_DISC | L2__CMD:
if (mb != NULL) {
err2 = send_FRMR (state, pf, x1, x2, cmd, 1, 1, 0, 0);
if (err == 0)
err = err2;
printf("%sERR_N 2\n",KERN_INFO );
err2 = msg_up (state, MDL_ERROR_IND, ERR_N);
if (err == 0)
err = err2;
break;
}
switch (state->status) {
case S_down:
case S_await_down:
err2 = xmit3 (state, 0, L2_UA | (pf ? L2_PF : 0));
if (err == 0)
err = err2;
break;
case S_await_up:
err2 = xmit3 (state, 0, L2_DM | (pf ? L2_PF : 0));
if (err == 0)
err = err2;
break;
case S_up:
err2 = flush_I (state);
if (err == 0)
err = err2;
err2 = xmit3 (state, 0, L2_UA | (pf ? L2_PF : 0));
if (err == 0)
err = err2;
err2 = msg_up (state, DL_RELEASE_IND, 0);
if (err == 0)
err = err2;
stop_T (1, err2);
if (err == 0)
err = err2;
stop_T (3, err2);
if (err == 0)
err = err2;
x75_setstate(state, S_down);
break;
case S_recover:
err2 = flush_I (state);
if (err == 0)
err = err2;
err2 = xmit3 (state, 0, L2_UA | (pf ? L2_PF : 0));
if (err == 0)
err = err2;
err2 = msg_up (state, DL_RELEASE_IND, 0);
if (err == 0)
err = err2;
stop_T (1, err2);
if (err == 0)
err = err2;
x75_setstate(state, S_down);
break;
case S_free:;
}
break;
case L2_DM:
if (mb != NULL) {
err2 = send_FRMR (state, pf, x1, x2, cmd, 1, 1, 0, 0);
if (err == 0)
err = err2;
printf("%sERR_N 3\n",KERN_INFO );
err2 = msg_up (state, MDL_ERROR_IND, ERR_N);
if (err == 0)
err = err2;
break;
}
switch (state->status) {
case S_down:
if (!pf) {
err2 = establish (state);
if (err == 0)
err = err2;
state->L3_req = 0;
}
break;
case S_await_up:
if (pf) {
err2 = flush_I (state);
if (err == 0)
err = err2;
err2 = msg_up (state, DL_RELEASE_IND, 0);
if (err == 0)
err = err2;
stop_T (1, err2);
if (err == 0)
err = err2;
x75_setstate(state, S_down);
}
break;
case S_await_down:
if (pf) {
err2 = flush_I (state);
if (err == 0)
err = err2;
err2 = msg_up (state, DL_RELEASE_CONF, 0);
if (err == 0)
err = err2;
stop_T (1, err2);
if (err == 0)
err = err2;
x75_setstate(state, S_down);
}
break;
case S_up:
case S_recover:
if (pf) {
printf("%sERR_B 1\n",KERN_INFO );
err2 = msg_up (state, MDL_ERROR_IND, ERR_B);
if (err == 0)
err = err2;
} else {
printf("%sERR_E 1\n",KERN_INFO );
err2 = msg_up (state, MDL_ERROR_IND, ERR_E);
if (err == 0)
err = err2;
err2 = establish (state);
if (err == 0)
err = err2;
state->L3_req = 0;
}
break;
case S_free:;
}
break;
case L2_UA:
if (mb != NULL) {
err2 = send_FRMR (state, pf, x1, x2, cmd, 1, 1, 0, 0);
if (err == 0)
err = err2;
printf("%sERR_N\n",KERN_INFO );
err2 = msg_up (state, MDL_ERROR_IND, ERR_N);
if (err == 0)
err = err2;
break;
}
switch (state->status) {
case S_up:
case S_down:
case S_recover:
printf("%sERR_CD 1\n",KERN_INFO );
err2 = msg_up (state, MDL_ERROR_IND, ERR_C | ERR_D);
if (err == 0)
err = err2;
break;
case S_await_up:
if (pf) {
if (state->L3_req) {
err2 = msg_up (state, DL_ESTABLISH_CONF, 0);
if (err == 0)
err = err2;
} else if (state->v_s != state->v_a) {
err2 = flush_I (state);
if (err == 0)
err = err2;
err2 = msg_up (state, DL_ESTABLISH_IND, 0);
if (err == 0)
err = err2;
}
x75_setstate(state, S_up);
stop_T (1, err2);
if (err == 0)
err = err2;
start_T (3, err2);
if (err == 0)
err = err2;
state->v_r = state->v_s = state->v_a = 0;
if(state->backenable)
(*state->backenable) (state->ref);
} else {
printf("%sERR_D 1\n",KERN_INFO );
err2 = msg_up (state, MDL_ERROR_IND, ERR_D);
}
if (err == 0)
err = err2;
break;
case S_await_down:
if (pf) {
err2 = msg_up (state, DL_RELEASE_CONF, 0);
if (err == 0)
err = err2;
stop_T (1, err2);
if (err == 0)
err = err2;
x75_setstate(state, S_down);
} else {
printf("%sERR_D 2\n",KERN_INFO );
err2 = msg_up (state, MDL_ERROR_IND, ERR_D);
}
if (err == 0)
err = err2;
break;
case S_free:;
}
break;
case L2_UI | L2__CMD:
if (mb == NULL) { /* Missing data. */
if (!isbroadcast) {
err2 = send_FRMR (state, pf, x1, x2, cmd, 1, 1, 0, 0);
if (err == 0)
err = err2;
}
break;
}
if ((err2 = (*state->recv) (state->ref, isbroadcast ? 3 : 1, mb)) != 0) {
if (err == 0)
err = err2;
freemsg (mb);
}
mb = NULL;
break;
case L2_XID | L2__CMD:
case L2_XID: /* TODO: Do something about XID frames. */
break;
case L2_FRMR:
case L2_FRMR | L2__CMD: /* technically an invalid frame, but replying with
FRMR here is _bad_ */
printf("%sERR_D 3\n",KERN_INFO );
err2 = msg_up (state, MDL_ERROR_IND, ERR_D);
if (err == 0)
err = err2;
if (state->status == S_up || state->status == S_recover) {
establish (state);
state->L3_req = 0;
}
break;
default:
err = -EINVAL;
err2 = send_FRMR (state, pf, x1, x2, cmd, 1, 0, 0, 0);
if (err == 0)
err = err2;
printf("%sERR_L 2\n",KERN_INFO );
err2 = msg_up (state, MDL_ERROR_IND, ERR_L);
if (err == 0)
err = err2;
break;
}
}
err2 = x75_check_pending (state, 0); /* if (err == 0) err = err2; */
if (mb != NULL)
freemsg (mb);
return /* err */ 0;
}
/*
* Enqueue frame to be sent out.
* Empty messages are silently discarded.
*/
int
x75_send (x75 state, char isUI, mblk_t * mb)
{
if (msgdsize(mb) <= 0)
freemsg(mb);
else if (isUI)
S_enqueue (&state->UI, mb);
else {
if(state->broadcast)
return -ENXIO;
S_enqueue (&state->I, mb);
}
state->asBroadcast = (isUI > 1);
(void) x75_check_pending (state, 0); /* Send the frame, if possible */
return 0;
}
/*
* Test if we can send.
*/
int
x75_cansend (x75 state, char isUI)
{
if(state->cansend != NULL)
(void)(*state->cansend) (state->ref); /* Trigger bringing L1 up */
if (isUI)
return (state->UI.nblocks < 3); /* arbitrary maximum */
else /* This allows us to enqueue one additional
* frame, which is a Good Thing. */
return (state->I.nblocks <= state->k);
}
/*
* Test if we can receive.
*/
int
x75_canrecv (x75 state)
{
/* Just ask the upper layer. */
return (*state->canrecv) (state->ref);
}
/*
* Take the X75 layer up / down.
*/
#ifdef CONFIG_DEBUG_ISDN
int
deb_x75_changestate (const char *deb_file,unsigned int deb_line, x75 state, uchar_t ind, char isabort)
#else
int
x75_changestate (x75 state, uchar_t ind, char isabort)
#endif
{
int ms = splstr ();
int err = 0, err2 = 0;
int nonestablish = 1;
#ifdef CONFIG_DEBUG_ISDN
if(state->debug & 0x10)
printf("%sx75.%d: State %d/%s for ind %d %d from %s:%d\n",KERN_DEBUG,state->debugnr,state->status,
x75_sname[state->status],ind,isabort,deb_file,deb_line);
#else
if(state->debug & 0x10)
printf("%sx75.%d: State %d/%s for ind %d %d\n",KERN_DEBUG,state->debugnr,state->status,
x75_sname[state->status],ind,isabort);
#endif
if (isabort)
goto doabort;
switch (ind) {
default:
err = -ENOENT;
break;
case PH_ACTIVATE_IND:
case PH_ACTIVATE_CONF:
msg_up (state, ind, 0);
break;
case DL_ESTABLISH_CONF: /* Force establishment, for situations where
* we dont need the initial handshake. This
* usually happens because an idiot
* implementor doesn't want to implement U
* frame handling for automode. */
if (state->status == S_up || state->status == S_recover)
break; /* Already established. */
if (state->debug & 0x10)
printf ("%sX75%d: Forced establish.\n",KERN_DEBUG, state->debugnr);
/* flush_I (state); */
state->errors = 0;
if (state->status != S_down && state->status != S_free)
stop_T (1, err2);
if (err == 0)
err = err2;
start_T (3, err2);
if (err == 0)
err = err2;
x75_setstate(state, S_up);
msg_up (state, DL_ESTABLISH_CONF, 0);
if(state->backenable)
(*state->backenable) (state->ref);
break;
case DL_ESTABLISH_REQ:
case DL_ESTABLISH_IND: /* Take it up. */
switch (state->status) {
case S_down:
case S_await_down:
if(ind == DL_ESTABLISH_IND /* && state->UI.first == NULL && state->UI.first == NULL */ ) {
if(0)printf("%sx75.%d: DL_ESTABLISH_IND, down, nothing done\n",KERN_DEBUG,state->debugnr);
break;
}
err = establish (state);
nonestablish = 0;
state->L3_req = 1;
state->errors = 0;
break;
case S_await_up:
if (ind == DL_ESTABLISH_REQ)
break;
#if 0 /* Q.921 says to do this, but I can't think of a reason to. */
/* This flush also breaks top-down on-demand connection setup,
i.e. starting up the lower layer automatically if the upper
layer has some data to deliver. */
err = flush_I (state);
#endif
state->L3_req = 1;
break;
case S_up:
case S_recover: /* L1 reestablishment */
if (ind == DL_ESTABLISH_REQ)
break;
err = flush_I (state);
err2 = establish (state);
nonestablish = 0;
if (err == 0)
err = err2;
state->L3_req = 1;
break;
default:;
}
break;
case DL_RELEASE_REQ: /* Take it down normally. */
state->errors = 0;
switch (state->status) {
case S_down:
err = msg_up (state, DL_RELEASE_CONF, 0);
break;
case S_up:
x75_setstate(state, S_await_down);
err = flush_I (state);
state->RC = 0;
err2 = xmit3 (state, 1, L2_DISC | L2_PF_U);
if (err == 0)
err = err2;
stop_T (3, err2);
if (err == 0)
err = err2;
restart_T (1, err2);
if (err == 0)
err = err2;
break;
case S_recover:
x75_setstate(state, S_await_down);
err = flush_I (state);
state->RC = 0;
err2 = xmit3 (state, 1, L2_DISC | L2_PF_U);
if (err == 0)
err = err2;
restart_T (1, err2);
if (err == 0)
err = err2;
break;
default:;
}
break;
case PH_DISCONNECT_IND:
case MDL_REMOVE_REQ:
switch (state->status) {
case S_await_up:
case S_down:
case S_up:
case S_recover:
err = kill_me (state, ind);
break;
case S_await_down:
case S_free:;
}
case DL_RELEASE_CONF:
case PH_DEACTIVATE_IND:
case PH_DEACTIVATE_CONF:
doabort: /* Just disconnect. The other side will
* either also realize that L1 is down, or
* time out eventually. */
switch (state->status) {
case S_await_up:
if (ind == PH_DEACTIVATE_IND)
break;
case S_down:
case S_up:
case S_recover:
err = kill_me (state, DL_RELEASE_IND);
break;
case S_await_down:
err = kill_me (state, DL_RELEASE_CONF);
break;
case S_free:;
}
x75_setstate(state, S_down);
}
if (err == 0) {
err2 = x75_check_pending (state, nonestablish);
if (err == 0)
err = err2;
}
splx (ms);
return err;
}
/*
* Initialize data.
*/
int
x75_initconn (x75 state)
{
bzero (&state->I, sizeof (struct _smallq));
bzero (&state->UI, sizeof (struct _smallq));
state->v_a = 0;
state->v_s = 0;
state->v_r = 0;
state->RC = 0;
state->status = S_down;
state->L3_req = 0;
state->RNR = 0;
state->sentRR = 1;
state->errors = 0;
state->ack_pend = 0;
state->inREJ = 0;
state->T1 = 0;
state->T3 = 0;
if (state->k == 0 || (state->k > (state->wide ? 127 : 7)))
state->k = 1;
if (state->N1 == 0)
state->N1 = 3;
if (state->RUN_T1 == 0)
state->RUN_T1 = 10;
if (state->RUN_T3 == 0)
state->RUN_T3 = 100;
if (state->RUN_T3 < state->RUN_T1 * 2)
state->RUN_T3 = state->RUN_T1 * 2;
if (state->send == NULL
|| state->recv == NULL
|| state->state == NULL)
return -EFAULT;
if(0)printf("%sX75 %d: Init %d %d\n",KERN_DEBUG,state->debugnr,state->RUN_T1,state->RUN_T3);
return 0;
}
#ifdef MODULE
static int do_init_module(void)
{
return 0;
}
static int do_exit_module(void)
{
return 0;
}
#endif