u-isdn/isdn_2/isdn_2.c

3219 lines
78 KiB
C

/* needs the "strlog" Stremas module, with log_printmsg visible, for now */
/*
* isdn_2
*
* Copyright (c) 1993-1995, Matthias Urlichs <urlichs@noris.de>.
*
*/
/*
TODO: C_lock_up is deactivated -> remove?
*/
#define UAREA
#include "f_module.h"
#include "kernel.h"
#include "primitives.h"
#include "isdn_2.h"
#include "f_signal.h"
#include "f_malloc.h"
#include "streams.h"
#include "stropts.h"
/* #ifdef DONT_ADDERROR */
#include "f_user.h"
/* #endif */
#ifndef __linux__
#include <sys/reg.h>
#include <sys/var.h>
#endif
#if 0
#include <sys/termios.h>
#include <fcntl.h>
#include <stddef.h>
#endif
#include "streamlib.h"
#include "isdn_23.h"
#include "isdn_12.h"
#include "x75lib.h"
#include "smallq.h"
#include "lap.h"
#include "sapi.h"
#include "isdn_limits.h"
#include "isdn_proto.h"
ushort_t hdrseq = 1;
extern void log_printmsg (void *log, const char *text, mblk_t * mp, const char*);
extern void logh_printmsg (void *log, const char *text, mblk_t * mp);
#ifdef CONFIG_DEBUG_ISDN
void logh__printmsg(unsigned int line,void *log,const char *text, mblk_t *mb)
{
printf("* %d",line);
logh_printmsg(log,text,mb);
}
#define logh_printmsg(a,b,c) logh__printmsg(__LINE__,a,b,c)
#endif
int isdn2_log = 0x00;
int isdn2_debug =
#ifdef CONFIG_DEBUG_ISDN
0x5016;
#else
0;
#endif
#ifdef DO_MULTI_TEI
#define State(card,ch) (card->state[ch])
#define N_TEI MAX_B /* zero is free */
#else
#define State(card,ch) (card->state[0])
#define N_TEI 0
#endif
/*
* Data.
*/
static struct _isdn2_card *isdn_card = NULL;
static struct _isdn2_chan isdn_chan = {};
static isdn2_chan isdnchan[NPORT] = { NULL,};
/* static struct _isdn2_state *isdn_state = NULL; */
/*
* Standard Streams driver information.
*/
static struct module_info isdn2_minfo =
{
0, "isdn", 0, INFPSZ, 200,100
};
static struct module_info isdn2_mtinfo =
{
0, "tisdn", 0, INFPSZ, 200,100
};
static qf_open isdn2_open;
static qf_close isdn2_close;
static qf_srv isdn2_wsrv, isdn2_rsrv;
static qf_put isdn2_wput;
static struct qinit isdn2_rinit =
{
putq, isdn2_rsrv, isdn2_open, isdn2_close, NULL, &isdn2_minfo, NULL
};
static struct qinit isdn2_winit =
{
isdn2_wput, isdn2_wsrv, NULL, NULL, NULL, &isdn2_minfo, NULL
};
static struct qinit isdn2_rtinit =
{
putq, isdn2_rsrv, isdn2_open, isdn2_close, NULL, &isdn2_mtinfo, NULL
};
static struct qinit isdn2_wtinit =
{
isdn2_wput, isdn2_wsrv, NULL, NULL, NULL, &isdn2_mtinfo, NULL
};
struct streamtab isdn_2info =
{&isdn2_rinit, &isdn2_winit, NULL, NULL};
struct streamtab isdn_2tinfo =
{&isdn2_rtinit, &isdn2_wtinit, NULL, NULL};
/* Flag for delaying sending up card info on open */
static char isdn2_notsent;
static void isdn2_sendcard (isdn2_card card);
/*
* Forward declarations for the X75/Q.921 interface
*/
static int D_state (isdn2_state state, uchar_t ind, short add);
static int D_cansend (isdn2_state state);
static int D_canrecv (isdn2_state state);
static int D_send (isdn2_state state, char cmd, mblk_t * data);
static int D_recv (isdn2_state state, char isUI, mblk_t * data);
static int D_backenable (isdn2_state state);
#ifdef CONFIG_DEBUG_ISDN
#define D_L1_up(a) deb_D_L1_up(__FILE__,__LINE__,(a))
static int deb_D_L1_up (const char *deb_file, unsigned int deb_line, isdn2_card card);
#define D_L1_down(a) deb_D_L1_down(__FILE__,__LINE__,(a))
static int deb_D_L1_down (const char *deb_file, unsigned int deb_line, isdn2_card card);
#else
static int D_L1_up (isdn2_card card);
static int D_L1_down (isdn2_card card);
#endif
#if 0
static void D_L1_not_up (isdn2_card card);
#endif
static void D_L1_re_up (isdn2_card card);
static void D_checkactive (isdn2_card card);
static void D_takedown (isdn2_card card);
static void poplist (queue_t * q, char flags);
static int isdn2_disconnect (isdn2_chan ch, uchar_t error);
static int pushlist (queue_t * q, mblk_t * mp, char flags);
#ifdef NEW_TIMEOUT
static int timer_sendcards;
#endif
/*
* Take down this L2 connection
*/
static int
D_kill_one (isdn2_state state, char ind)
{
isdn2_card card;
int ms = splstr ();
int ch;
#ifdef DO_MULTI_TEI
ch = state->bchan;
#else
ch = 0;
#endif
if (isdn2_debug & 0x10)
printf ("%sD_kill_one %x %p %d\n",KERN_DEBUG, state->SAPI, state, ind);
/* Unhook the state info from the card's chain */
card = state->card;
if (card == NULL) /* should not happen */
state = NULL;
else if (card->state[ch] == state)
card->state[ch] = state->next;
else {
isdn2_state nstate;
for (nstate = card->state[ch]; nstate != NULL; nstate = nstate->next) {
if (nstate->next == state) {
nstate->next = state->next;
break;
}
}
if (nstate == NULL)
state = NULL;
}
/* Tell X75 that the channel is dropped */
if (state != NULL) {
if(!(card->card->modes & CHM_INTELLIGENT))
x75_changestate (&state->state, ind, 1);
free(state);
}
splx (ms);
D_checkactive (card);
if (state != NULL)
return 0;
else
return -ENOENT;
}
/* Take down / notify all of this card's L2 connections */
#ifdef CONFIG_DEBUG_ISDN
#define D_kill_all(a,b) deb_D_kill_all(__FILE__,__LINE__,a,b)
static int
deb_D_kill_all (const char *deb_file, unsigned int deb_line, isdn2_card card, char ind)
#else
static int
D_kill_all (isdn2_card card, char ind)
#endif
{
int err;
int i;
int ch;
if (isdn2_debug & 0x10) {
#ifdef CONFIG_DEBUG_ISDN
printf ("%sD_kill_all %s:%d %d:%d\n",KERN_DEBUG, deb_file,deb_line, card->nr, ind);
#else
printf ("%sD_kill_all %d:%d\n",KERN_DEBUG, card->nr, ind);
#endif
}
if (ind == 0) {
for(ch=0;ch <= N_TEI; ch++) {
while (card->state[ch] != NULL) {
if ((err = D_kill_one (card->state[ch], 0)) != 0)
return err;
}
}
} else {
for(ch=0;ch <= N_TEI; ch++) {
isdn2_state state, nstate;
for (state = card->state[ch]; state != NULL; state = nstate) {
nstate = state->next;
if(card->card->modes & CHM_INTELLIGENT)
D_state(state,ind,0);
else
x75_changestate (&state->state, ind, 0);
}
}
}
/*
* Now hit all connections hanging off that card.
*/
if ((ind < IND_UP_FIRST) || (ind > IND_UP_LAST)) {
for (i = 0; i < MAXCHAN; i++) {
if (card->chan[i] != NULL && card->chan[i]->qptr != NULL) {
#if 0
putctlerr (card->chan[i]->qptr, -ENXIO);
#else
isdn2_disconnect (card->chan[i], 0xFF);
#endif
}
}
}
D_checkactive (card);
return 0;
}
/*
* Timeout procedure to kill a card if there's no connection on it for a few
* seconds. Only called for nonintelligent cards.
*/
static void
D_takedown (isdn2_card card)
{
if (card->timedown == 1) {
card->timedown = 0;
D_L1_down (card);
}
return;
}
/*
* Check if there's a connection running on this card. If not, setup a timeout
* to take the D channel and L1 down, in a few seconds.
*/
static void
D_checkactive (isdn2_card card)
{
isdn2_state state;
uchar_t ch;
if(card == NULL)
return;
#if 1 /* def DO_L2_DOWN */
if (card->status != C_up)
return;
if (card->timedown == 1) {
card->timedown = 0;
#ifdef OLD_TIMEOUT
untimeout (D_takedown, card);
#else
untimeout (card->timer_takedown);
#endif
}
for(ch=0; ch <= N_TEI; ch++) {
for (state = card->state[ch]; state != NULL; state = state->next) {
if (state->state.status != S_free && state->state.status != S_down)
return;
}
}
if (!(card->card->modes & CHM_INTELLIGENT) && !(card->timedown)) {
card->timedown = 1;
#ifdef NEW_TIMEOUT
card->timer_takedown =
#endif
timeout ((void *)D_takedown, card, 2 * HZ);
}
#endif /* DO_L2_DOWN */
}
/*
* Install a handler for connections with this SAPI.
*/
static int
D_register (isdn2_card card, uchar_t SAPI, uchar_t ch, uchar_t broadcast)
{
isdn2_state state;
int ms = splstr ();
if (isdn2_debug & 0x40)
printf ("%sD_register %d %x/%x\n",KERN_DEBUG,
card->nr, SAPI,card->TEI[ch]);
/* Check if this SAPI is in use. */
if(card->card->modes & CHM_INTELLIGENT) {
if(card->state[ch] != NULL)
return -EEXIST;
} else {
for (state = card->state[ch]; state != NULL; state = state->next) {
if (state->SAPI == SAPI) {
splx (ms);
if (isdn2_debug & 0x10)
printf ("%sD_register: State table already present for %d:%x/%x\n",KERN_DEBUG,
card->nr, SAPI, card->TEI[ch]);
return -EEXIST;
}
}
}
state = malloc(sizeof(*state));
if (state == NULL) {
splx (ms);
if (isdn2_debug & 0x10)
printf ("%sD_register: No state table free for %d:%x/%x\n",KERN_DEBUG,
card->nr, SAPI, card->TEI[ch]);
return -ENOMEM;
}
bzero(state,sizeof(*state));
/*
* Got a free state. Now setup and install the x75 handler. The protocol is
* actually Q.921 but the differences are less than minimal.
*/
state->next = card->state[ch];
card->state[ch] = state;
#ifdef DO_MULTI_TEI
state->bchan = ch;
#endif
state->card = card;
state->SAPI = SAPI;
if(!(card->card->modes & CHM_INTELLIGENT)) {
state->state.send = (P_data) & D_send;
state->state.recv = (P_data) & D_recv;
state->state.cansend = (P_candata) & D_cansend;
state->state.canrecv = (P_candata) & D_canrecv;
state->state.flush = NULL;
state->state.state = (P_state) & D_state;
state->state.backenable = (P_backenable) & D_backenable;
state->state.ref = state;
state->state.debugnr = SAPI;
state->state.broadcast = (broadcast != 0);
state->state.RUN_T1 = 15; /* Yes this is slow. This is intentional. Grrr. */
state->state.RUN_T3 = 150; /* Ditto. */
x75_initconn (&state->state);
if(isdn2_debug & 0x8000)
state->state.debug = 0xFFF7;
state->state.wide = 1;
state->state.offset = 2;
}
splx (ms);
D_checkactive (card);
return 0;
}
/*
* State change for this connection. Called by X75.
*/
static int
sendstate (isdn2_card card, uchar_t ch, uchar_t SAPI, uchar_t ind, short add)
{
isdn23_hdr hdr;
mblk_t *mb;
if (isdn2_debug & 0x40)
printf ("%ssendstate %d %x:%x\n",KERN_DEBUG, card->nr, ind, add);
if (ind == MDL_ERROR_IND) {
if(add & (ERR_C | ERR_D | ERR_G /* | ERR_H */ | ERR_I )) {
printf("%s\nISDN Fatal Error, TEI cleared\n",KERN_DEBUG);
card->TEI[ch] = TEI_BROADCAST;
}
}
mb = allocb (sizeof (struct _isdn23_hdr), BPRI_HI);
if (mb == NULL) {
if (isdn2_debug & 0x10)
printf ("%ssendstate: nomem to send ind %x:%x for %d:%x/%x\n",KERN_DEBUG, ind, add,
card->nr, SAPI, card->TEI[ch]);
return -ENOMEM;
}
hdr = ((isdn23_hdr) mb->b_wptr)++;
switch (ind) {
case DL_ESTABLISH_IND:
case DL_ESTABLISH_CONF:
hdr->key = HDR_OPENPROT;
hdr->seqnum = hdrseq; hdrseq += 2;
hdr->hdr_openprot.card = card->nr;
hdr->hdr_openprot.SAPI = SAPI;
#ifdef DO_MULTI_TEI
hdr->hdr_openprot.bchan = ch;
#endif
hdr->hdr_openprot.ind = ind;
break;
case DL_RELEASE_IND:
case DL_RELEASE_CONF:
hdr->key = HDR_CLOSEPROT;
hdr->seqnum = hdrseq; hdrseq += 2;
hdr->hdr_closeprot.card = card->nr;
hdr->hdr_closeprot.SAPI = SAPI;
hdr->hdr_closeprot.ind = ind;
#ifdef DO_MULTI_TEI
hdr->hdr_closeprot.bchan = ch;
#endif
break;
default:
hdr->key = HDR_NOTIFY;
hdr->seqnum = hdrseq; hdrseq += 2;
hdr->hdr_notify.card = card->nr;
hdr->hdr_notify.SAPI = SAPI;
#ifdef DO_MULTI_TEI
hdr->hdr_notify.bchan = ch;
#endif
hdr->hdr_notify.ind = ind;
hdr->hdr_notify.add = add;
break;
}
if (isdn_chan.qptr != NULL) {
if(isdn2_debug & 0x2000) logh_printmsg (NULL, "Up", mb);
if(canput(isdn_chan.qptr->q_next))
putnext (isdn_chan.qptr, mb);
else {
freemsg(mb);
return -ENOSPC;
}
} else {
freemsg (mb);
return -ENXIO;
}
return 0;
}
/*
* State change for this connection. Called by X75.
*/
static int
D_state (isdn2_state state, uchar_t ind, short add)
{
uchar_t ch;
int err;
#ifdef DO_MULTI_TEI
ch = state->bchan;
#else
ch = 0;
#endif
err = sendstate(state->card,ch,state->SAPI,ind,add);
D_checkactive (state->card);
return err;
}
void
isdn2_chstate (struct _isdn1_card *card, uchar_t ind, short add)
{
isdn2_card ctl;
ctl = (isdn2_card) card->ctl;
if (ctl == NULL)
return;
sendstate(ctl,0,0,ind,add);
}
static const char *
statename(enum C_state status)
{
switch (status) {
case C_lock_up:
return "C_lock_up";
break;
case C_up:
return "C_up";
break;
case C_down:
return "C_down";
break;
case C_wont_up:
return "C_wont_up";
break;
case C_wont_down:
return "C_wont_down";
break;
case C_await_up:
return "C_await_up";
break;
case C_await_back_up:
return "C_await_back_up";
break;
case C_await_down:
return "C_await_down";
break;
default:
return "C_unknown";
break;
}
}
#ifdef CONFIG_DEBUG_ISDN
#define set_card_status(a,b) deb_set_card_status(__FILE__,__LINE__,a,b)
#endif
/*
* Set card status, logging
*/
static void
#ifdef CONFIG_DEBUG_ISDN
deb_set_card_status (const char *deb_file, unsigned int deb_line, isdn2_card card, enum C_state status)
#else
set_card_status (isdn2_card card, enum C_state status)
#endif
{
char cid[5];
*(unsigned long *)cid = card->id;
cid[4]='\0';
if(isdn2_debug & 0x10) {
const char *sold = statename(card->status);
const char *snew = statename(status);
#ifdef CONFIG_DEBUG_ISDN
printf ("%s!!! %4s: %s -> %s at %s %d\n",KERN_DEBUG, cid, sold,snew, deb_file,deb_line);
#else
printf ("%s!!! %4s: %s -> %s\n",KERN_DEBUG, cid, sold,snew);
#endif
}
if (status == card->status)
return;
switch(card->status) {
case C_await_up:
#if 0
if(card->timeup) {
card->timeup = 0;
#ifdef OLD_TIMEOUT
untimeout (D_L1_not_up, crd);
#else
untimeout (card->timer_not_up);
#endif
}
#endif
break;
case C_wont_up:
if(card->timeup) {
card->timeup = 0;
#ifdef OLD_TIMEOUT
untimeout (D_L1_re_up, crd);
#else
untimeout (card->timer_not_up);
#endif
}
break;
default:;
}
card->status = status;
if(card->status != C_up) {
if (card->timedown == 1) {
card->timedown = 0;
#ifdef OLD_TIMEOUT
untimeout (D_takedown, card);
#else
untimeout (card->timer_takedown);
#endif
}
}
switch(card->status) {
case C_await_up:
#if 0
card->timeup = 1;
#ifdef NEW_TIMEOUT
card->timer_not_up =
#endif
timeout ((void *)D_L1_not_up, card, (HZ*3)/2);
#endif
break;
case C_wont_up:
card->timeup = 1;
#ifdef NEW_TIMEOUT
card->timer_not_up =
#endif
timeout ((void *)D_L1_re_up, card, HZ * 30);
break;
default:;
}
}
static void
D_L1_re_up(isdn2_card card)
{
if(!card->timeup)
return;
card->timeup = 0;
set_card_status(card,C_down);
if(isdn_chan.qptr != NULL)
D_L1_up(card);
else
card->offline = 0;
}
#if 0
/*
* Timeout procedure to notify upper layers when L1 doesn't come up. The usual
* reason for this is that somebody pulled the ISDN cable.
*/
static void
D_L1_not_up (isdn2_card card)
{
mblk_t *mb;
isdn23_hdr hdr;
if(!card->timeup)
return;
card->timeup = 0;
if(card->status != C_await_up) {
printf("%sD_L1_not_up called at wrong time! S %d\n",KERN_DEBUG,card->status);
return;
}
if (isdn2_debug & 0x10)
printf ("%sisdn: Card %d: Disconnected??\n",KERN_DEBUG, card->nr);
if(!card->offline)
D_kill_all (card, PH_DISCONNECT_IND);
set_card_status (card, C_wont_up);
D_L1_down (card);
if(!card->offline) {
card->offline = 1;
mb = allocb (sizeof (struct _isdn23_hdr), BPRI_HI);
if (mb == NULL) {
if (isdn2_debug & 0x10)
printf ("%sD_L1_not_up: no memory\n",KERN_DEBUG);
return;
}
hdr = ((isdn23_hdr) mb->b_wptr)++;
hdr->key = HDR_NOCARD;
hdr->seqnum = hdrseq; hdrseq += 2;
hdr->hdr_nocard.card = card->nr;
if (isdn_chan.qptr != NULL) {
if(isdn2_debug & 0x2000) logh_printmsg (NULL, "Up", mb);
if(canput(isdn_chan.qptr->q_next)) {
putnext (isdn_chan.qptr, mb);
return;
}
}
freemsg (mb);
}
}
#endif
/*
* Upper level wants to send data -- (re)start L1.
*/
static int
#ifdef CONFIG_DEBUG_ISDN
deb_D_L1_up (const char *deb_file, unsigned int deb_line, isdn2_card card)
#else
D_L1_up (isdn2_card card)
#endif
{
if (isdn2_debug & 0x48)
printf ("%sD_L1_up %d: S was %d\n",KERN_DEBUG, card->nr,card->status);
if (card->card == NULL) {
if (isdn2_debug & 0x10)
printf ("%sD_L1_up: Card %d not registered\n",KERN_DEBUG, card->nr);
return -ENXIO;
}
switch (card->status) {
case C_await_up:
#ifdef CONFIG_DEBUG_ISDN
deb_set_card_status (deb_file,deb_line, card, C_await_up); /* Re-set the timeout */
#else
set_card_status (card, C_await_up); /* Re-set the timeout */
#endif
break;
case C_up:
case C_lock_up:
break;
case C_wont_up:
return -EIO;
case C_await_down:
case C_await_back_up:
if(!(card->card->modes & CHM_INTELLIGENT)) {
set_card_status (card, C_await_back_up);
break;
} /* else FALL THRU */
case C_down:
case C_wont_down:
if(!(card->card->modes & CHM_INTELLIGENT)) {
#ifdef CONFIG_DEBUG_ISDN
deb_set_card_status (deb_file,deb_line, card, C_await_up);
#else
set_card_status (card, C_await_up);
#endif
(*card->card->ch_mode) (card->card, 0, M_ON, 0);
}
break;
}
D_checkactive (card);
return 0;
}
/*
* Take the card down. Called via timeout or when there are no active
* connections for a few seconds.
*/
static int
#ifdef CONFIG_DEBUG_ISDN
deb_D_L1_down (const char *deb_file, unsigned int deb_line, isdn2_card card)
#else
D_L1_down (isdn2_card card)
#endif
{
if (isdn2_debug & 0x40)
printf ("%sD_L1_down %d\n",KERN_DEBUG, card->nr);
if (card->card == NULL) {
if (isdn2_debug & 0x10)
printf ("%sD_L1_down: Card %d not registered\n",KERN_DEBUG, card->nr);
return -ENXIO;
}
if (isdn2_debug & 0x10)
printf ("%sD_L1_Down: State was %d\n",KERN_DEBUG, card->status);
switch (card->status) {
case C_await_down:
case C_await_back_up:
case C_down:
case C_wont_up:
(*card->card->ch_mode) (card->card, 0, M_OFF, 0);
return 0;
case C_wont_down:
case C_lock_up:
break;
case C_await_up:
#ifdef CONFIG_DEBUG_ISDN
deb_set_card_status (deb_file,deb_line, card, C_down);
#else
set_card_status (card, C_down);
#endif
if (isdn_chan.qptr != NULL)
(*card->card->ch_mode) (card->card, 0, M_STANDBY, 1);
else
(*card->card->ch_mode) (card->card, 0, M_OFF, 0);
break;
case C_up:
if (isdn_chan.qptr != NULL) {
if(card->card->modes & CHM_INTELLIGENT) {
#ifdef CONFIG_DEBUG_ISDN
deb_set_card_status(deb_file,deb_line, card, C_down);
#else
set_card_status(card, C_down);
#endif
} else {
#ifdef CONFIG_DEBUG_ISDN
deb_set_card_status (deb_file,deb_line, card, C_await_down);
#else
set_card_status (card, C_await_down);
#endif
}
(*card->card->ch_mode) (card->card, 0, M_STANDBY, 1);
} else {
#ifdef CONFIG_DEBUG_ISDN
deb_set_card_status (deb_file,deb_line, card, C_down);
#else
set_card_status (card, C_down);
#endif
(*card->card->ch_mode) (card->card, 0, M_OFF, 0);
}
break;
}
D_checkactive (card);
return 0;
}
/*
* Data has been sent; enable the downstream queue. Called from X75.
*/
static int
D_backenable (isdn2_state state)
{
if (isdn2_debug & 0x40)
printf ("%sD_backenable %p\n",KERN_DEBUG, state);
if (isdn_chan.qptr != NULL)
qenable (WR (isdn_chan.qptr));
return 0;
}
/*
* Check if there's room on the upstream queue. Called from X75.
*/
static int
D_canrecv (isdn2_state state)
{
if (isdn2_debug & 0x40)
printf ("%sD_canrecv %d ",KERN_DEBUG, state->card->nr);
if (isdn_chan.qptr == 0 || isdn_chan.qptr->q_next == NULL) {
#ifdef CONFIG_DEBUG_ISDN
printf("%s-NoStream",KERN_DEBUG);
#endif
return 0;
} else
return (canput (isdn_chan.qptr->q_next));
}
/*
* Send data upstream. Called from X75.
*/
static int
D_recv (isdn2_state state, char isUI, mblk_t * mb)
{
mblk_t *mb2;
isdn23_hdr hdr;
#ifdef CONFIG_DEBUG_STREAMS
if(msgdsize(mb) < 0)
return 0;
#endif
if (isdn2_debug & 0x40)
printf ("%sD_recv %d %d %d\n",KERN_DEBUG, state->card->nr, msgdsize(mb), isUI);
mb2 = allocb (sizeof (struct _isdn23_hdr), BPRI_MED);
if (mb2 == NULL) {
if (isdn2_debug & 0x10)
printf ("%sD_recv: no mblk for header\n",KERN_DEBUG);
return -ENOMEM;
}
hdr = ((isdn23_hdr) mb2->b_wptr)++;
if (isUI) {
hdr->key = HDR_UIDATA;
hdr->seqnum = hdrseq; hdrseq += 2;
hdr->hdr_uidata.card = state->card->nr;
hdr->hdr_uidata.SAPI = state->SAPI;
#ifdef DO_MULTI_TEI
hdr->hdr_uidata.bchan = state->bchan;
#endif
hdr->hdr_uidata.len = dsize (mb);
hdr->hdr_uidata.broadcast = (isUI & 2);
} else {
hdr->key = HDR_DATA;
hdr->seqnum = hdrseq; hdrseq += 2;
hdr->hdr_data.card = state->card->nr;
hdr->hdr_data.SAPI = state->SAPI;
#ifdef DO_MULTI_TEI
hdr->hdr_data.bchan = state->bchan;
#endif
hdr->hdr_data.len = dsize (mb);
}
linkb (mb2, mb);
if (isdn_chan.qptr != NULL) {
if(isdn2_debug & 0x2000) logh_printmsg (NULL, "Up", mb2);
if(canput(isdn_chan.qptr->q_next)) {
putnext (isdn_chan.qptr, mb2);
return 0;
}
freeb(mb2);
return -ENOSPC;
}
freeb (mb2);
return -ENXIO;
}
/*
* Send data downstream. Prepend SAPI and TEI. Called from X75.
*/
static int
D_send (isdn2_state state, char cmd, mblk_t * mb)
/* cmd=2: send as broadcast */
{
struct _isdn1_card *crd;
int err;
uchar_t ch;
#ifdef CONFIG_DEBUG_STREAMS
if(msgdsize(mb) < 0)
return 0;
#endif
if (isdn2_debug & 0x40)
printf ("%sD_send %d %d %d %d\n",KERN_DEBUG, state->card->nr, state->card->status, msgdsize(mb), cmd);
if ((crd = state->card->card) == NULL) {
if (isdn2_debug & 0x10)
printf ("%s -- no card\n",KERN_DEBUG);
return -ENXIO;
}
#ifdef DO_MULTI_TEI
ch=state->bchan;
#else
ch=0;
#endif
if (state->card->status != C_up && state->card->status != C_lock_up) {
if (isdn2_debug & 0x10)
printf ("%sD_send: %d:%x/%x sending, state %d\n",KERN_DEBUG, state->card->nr,
state->SAPI, state->card->TEI[ch], state->card->status);
if (isdn2_debug & 0x10)
printf ("%s -- card down 1\n",KERN_DEBUG);
if ((err = D_L1_up (state->card)) == 0)
err = -EAGAIN;
return err;
}
if (!(*crd->cansend) (crd, 0)) {
if (isdn2_debug & 0x10)
printf ("%s -- can't send\n",KERN_DEBUG);
return -EAGAIN;
}
if (!(crd->modes & CHM_INTELLIGENT) && !(cmd & 2)) { /* TEI necessary? */
if (state->card->TEI[ch] == TEI_BROADCAST) { /* No TEI yet. Alert L3. */
mblk_t *mp;
isdn23_hdr hdr;
if (isdn2_debug & 0x10)
printf ("%sD_send: %d:%x/NO_TEI\n",KERN_DEBUG, state->card->nr, state->SAPI);
if ((mp = allocb (sizeof (struct _isdn23_hdr), BPRI_MED)) == NULL) {
if (isdn2_debug & 0x10)
printf ("%sD_recv: no mblk for TEIreq\n",KERN_DEBUG);
return -EAGAIN;
}
hdr = ((isdn23_hdr) mp->b_wptr)++;
hdr->key = HDR_TEI;
hdr->seqnum = hdrseq; hdrseq += 2;
hdr->hdr_tei.card = state->card->nr;
hdr->hdr_tei.TEI = state->card->TEI[ch];
#ifdef DO_MULTI_TEI
hdr->hdr_tei.bchan = ch;
#endif
if (isdn_chan.qptr != NULL) {
if(isdn2_debug & 0x2000) logh_printmsg (NULL, "Up", mp);
if(!canput(isdn_chan.qptr->q_next)) {
freeb(mp);
return -ENOSPC;
}
putnext (isdn_chan.qptr, mp);
state->card->TEI[ch] = TEI_REQUESTED;
} else {
freeb (mp);
return -ENXIO;
}
return -EAGAIN;
} else if (state->card->TEI[ch] == TEI_REQUESTED)
return -EAGAIN;
}
/*
* If there's room in front, don't bother with a new mblk.
*/
if(crd->modes & CHM_INTELLIGENT) {
if(isdn2_log & 0x10) {
printf ("%s*** %d", KERN_DEBUG,state->card->nr);
log_printmsg (NULL, " Send", mb, KERN_DEBUG);
}
err = (*crd->send)(crd,0,mb);
} else if (DATA_START(mb) + 2 <= mb->b_rptr && DATA_REFS(mb) == 1) {
*--mb->b_rptr = (((cmd & 2) ? TEI_BROADCAST : state->card->TEI[ch]) << 1) | 1;
*--mb->b_rptr = (state->SAPI << 2) | ((cmd & 1) ? 0 : 2);
if(isdn2_log & 0x20) {
printf ("%s*** %d", KERN_DEBUG,state->card->nr);
log_printmsg (NULL, " Send", mb, KERN_DEBUG);
}
if(state->card->flags & HDR_CARD_DEBUG) {
isdn23_hdr hdr;
mblk_t *m1 = allocb(sizeof(*hdr),BPRI_MED);
mblk_t *m2 = dupmsg(mb);
if (m1 == NULL || m2 == NULL) {
if(m1 != NULL)
freemsg(m1);
if(m2 != NULL)
freemsg(m2);
} else {
hdr = ((isdn23_hdr) m1->b_wptr)++;
hdr->key = HDR_RAWDATA;
hdr->seqnum = hdrseq; hdrseq += 2;
hdr->hdr_rawdata.card = state->card->nr;
hdr->hdr_rawdata.dchan = 1;
hdr->hdr_rawdata.len = dsize (m2);
hdr->hdr_rawdata.flags = 1;
linkb (m1, m2);
if(canput(isdn_chan.qptr->q_next))
putnext (isdn_chan.qptr, m1);
else
freemsg(m1);
}
}
if(isdn2_log & 0x10) {
printf ("%s*** %d", KERN_DEBUG,state->card->nr);
log_printmsg (NULL, " Send", mb, KERN_DEBUG);
}
if ((err = (*crd->send) (crd, 0, mb)) != 0)
mb->b_rptr += 2;
} else {
mblk_t *mb2 = allocb (2, BPRI_HI);
if (mb2 == NULL) {
if (isdn2_debug & 0x10)
printf ("%sD_send: No mem to send %s to %d:%x/%x\n",KERN_DEBUG, cmd ? "Cmd" : "Resp", state->card->nr, state->SAPI, state->card->TEI[ch]);
return -ENOMEM;
}
*mb2->b_wptr++ = (state->SAPI << 2) | ((cmd & 1) ? 0 : 2);
*mb2->b_wptr++ = (((cmd & 2) ? TEI_BROADCAST : state->card->TEI[ch]) << 1) | 1;
linkb (mb2, mb);
if(isdn2_log & 0x20) {
printf ("%s*** %d", KERN_DEBUG,state->card->nr);
log_printmsg (NULL, " Send", mb2, KERN_DEBUG);
}
if(state->card->flags & HDR_CARD_DEBUG) {
isdn23_hdr hdr;
mblk_t *m1 = allocb(sizeof(*hdr),BPRI_MED);
mblk_t *m2 = dupmsg(mb2);
if (m1 == NULL || m2 == NULL) {
if(m1 != NULL)
freemsg(m1);
if(m2 != NULL)
freemsg(m2);
} else {
hdr = ((isdn23_hdr) m1->b_wptr)++;
hdr->key = HDR_RAWDATA;
hdr->seqnum = hdrseq; hdrseq += 2;
hdr->hdr_rawdata.card = state->card->nr;
hdr->hdr_rawdata.dchan = 1;
hdr->hdr_rawdata.len = dsize (m2);
hdr->hdr_rawdata.flags = 1;
linkb (m1, m2);
if(canput(isdn_chan.qptr->q_next))
putnext (isdn_chan.qptr, m1);
else
freemsg(m1);
}
}
if(isdn2_log & 0x10) {
printf ("%s*** %d", KERN_DEBUG,state->card->nr);
log_printmsg (NULL, " Send", mb2, KERN_DEBUG);
}
if ((err = (*crd->send) (crd, 0, mb2)) != 0)
freeb (mb2);
}
D_checkactive(state->card);
if(err != 0)
printf("%sD_Send Err %d ",KERN_DEBUG,err);
return err;
}
/*
* Check if there's room on the downstream queue. Called from X75.
* (Or directly, for intelligent cards.)
*/
static int
D_cansend (isdn2_state state)
{
struct _isdn1_card *crd;
if (isdn2_debug & 0x40)
printf ("%sD_cansend %d %d", KERN_DEBUG,state->card->nr, state->card->status);
if ((crd = state->card->card) == NULL) {
if (isdn2_debug & 0x10)
printf ("\n%s -- card NULL\n",KERN_DEBUG);
return 0;
}
if (isdn2_debug & 0x40)
printf ("cs %p\n", crd->cansend);
if(!(state->card->card->modes & CHM_INTELLIGENT)) {
if (state->card->status != C_up && state->card->status != C_lock_up) {
if (isdn2_debug & 0x10)
printf ("%s -- card down 2\n",KERN_DEBUG);
(void) D_L1_up (state->card);
return 0; /* Not yet. */
}
}
if (!(*crd->cansend) (crd, 0)) {
if (isdn2_debug & 0x10)
printf ("%s -- card busy\n",KERN_DEBUG);
return 0;
}
return 1;
}
/*
* Look for the connection.
*/
static isdn2_state
D__findstate (isdn2_card card, uchar_t SAPI, uchar_t ch)
{
isdn2_state state = card->state[ch];
if(card->card->modes & CHM_INTELLIGENT)
return state;
if(isdn2_debug&0x900) printf("%sD_findstate %d:%x/%x:",KERN_DEBUG,card->nr,SAPI,card->TEI[ch]);
while (state != NULL) {
if(isdn2_debug&0x900) printf("%s_%x",KERN_DEBUG,state->SAPI);
if (state->SAPI == SAPI)
break;
state = state->next;
}
if (state == NULL) {
if ((isdn2_debug&0x910) == 0x10)
printf("%sD_findstate %d:%x/%x:",KERN_DEBUG,card->nr,SAPI,card->TEI[ch]);
if (isdn2_debug & 0x900)
printf ("%s not found\n",KERN_DEBUG);
}
return state;
}
/**
** ISDN card handling
**/
/* --> isdn_12.h */
int
isdn2_register (struct _isdn1_card *card, long id)
{
/* int cd; */
int ms = splstr ();
isdn2_card crd;
uchar_t ch;
uchar_t nr, found_nr;
if (isdn2_debug & 0x10)
printf ("%sisdn2_register %p %lx\n",KERN_DEBUG, card, id);
nr = 1;
do {
nr++;
found_nr = 0;
for (crd = isdn_card; crd != NULL; crd = crd->next) {
if (crd->id == id) {
splx (ms);
if (isdn2_debug & 0x10)
printf ("%sISDN register: ID %lx already registered as %d\n",KERN_DEBUG, id, crd->nr);
return -EEXIST;
}
if (crd->nr == nr) {
found_nr++;
break;
}
}
} while(found_nr);
crd = malloc(sizeof(*crd));
if (crd == NULL) {
if (isdn2_debug & 0x10)
printf ("%sisdn2_register: no free card store\n",KERN_DEBUG);
splx (ms);
return -EBUSY;
}
bzero(crd,sizeof(*crd));
crd->next = isdn_card;
isdn_card = crd;
crd->card = card;
card->ctl = crd;
if (card->nr_chans > MAXCHAN - MAX_D)
card->nr_chans = MAXCHAN - MAX_D;
set_card_status (crd, C_down);
crd->id = id;
crd->nr = nr;
for(ch=0;ch <= N_TEI; ch++)
crd->TEI[ch] = TEI_BROADCAST;
(*card->ch_mode) (card, 0, M_OFF, 1);
splx (ms);
isdn2_sendcard (crd);
return 0;
}
/* --> isdn_12.h */
int
isdn2_unregister (struct _isdn1_card *card)
{
int ms = splstr ();
mblk_t *mb;
isdn2_card crd;
isdn23_hdr hdr;
isdn2_card *pcrd = &isdn_card;
if (isdn2_debug & 0x10)
printf ("%sisdn2_unregister %p, 2 is %p\n",KERN_DEBUG, card,card->ctl);
crd = (isdn2_card) card->ctl;
if (crd == NULL) {
splx (ms);
if (isdn2_debug & 0x10)
printf ("%sisdn2_unregister: card not registered\n",KERN_DEBUG);
return -ENODEV;
}
while(*pcrd != NULL && *pcrd != crd)
pcrd = &(*pcrd)->next;
if (*pcrd == NULL) {
splx (ms);
printf ("%sisdn2_unregister: card chain broken\n",KERN_DEBUG);
return -EIO;
}
set_card_status(crd,C_down);
D_kill_all (crd, 0);
if(!crd->offline) {
mb = allocb (sizeof (struct _isdn23_hdr), BPRI_HI);
if (mb == NULL) {
if (isdn2_debug & 0x10)
printf ("%sisdn2_unregister: no memory\n",KERN_DEBUG);
return -ENOMEM;
}
hdr = ((isdn23_hdr) mb->b_wptr)++;
hdr->key = HDR_NOCARD;
hdr->seqnum = hdrseq; hdrseq += 2;
hdr->hdr_nocard.card = crd->nr;
if (isdn_chan.qptr != NULL) {
if(isdn2_debug & 0x2000) logh_printmsg (NULL, "Up", mb);
if(canput(isdn_chan.qptr->q_next))
putnext (isdn_chan.qptr, mb);
else
freemsg(mb);
} else
freemsg (mb);
}
*pcrd = crd->next;
splx (ms);
free(crd);
return 0;
}
/* --> isdn_12.h */
void
isdn2_new_state (struct _isdn1_card *card, char state)
{
isdn23_hdr hdr;
mblk_t *mb;
isdn2_card ctl;
ctl = (isdn2_card) card->ctl;
if (ctl == NULL)
return /* ENXIO */ ;
if (isdn2_debug & 0x40)
printf ("%sisdn2_new_state %d %d %d\n",KERN_DEBUG, ctl->nr, ctl->status, state);
mb = allocb (sizeof (struct _isdn23_hdr), BPRI_HI);
if (mb == NULL) {
if (state != 1)
D_kill_all (ctl, state ? PH_DISCONNECT_IND : PH_DEACTIVATE_IND);
if (isdn2_debug & 0x10)
printf ("%sNew_State: No hdr mem for %d\n",KERN_DEBUG, ctl->nr);
return /* ENOMEM */ ;
}
hdr = ((isdn23_hdr) mb->b_wptr)++;
hdr->key = HDR_NOTIFY;
hdr->seqnum = hdrseq; hdrseq += 2;
hdr->hdr_notify.card = ctl->nr;
hdr->hdr_notify.SAPI = SAPI_INVALID; /* all */
if (state == 2) { /* Card is bouncing */
switch (ctl->status) {
case C_lock_up:
freemsg (mb);
return;
case C_await_back_up:
case C_await_down:
hdr->hdr_notify.ind = PH_DISCONNECT_IND;
set_card_status (ctl, C_down);
break;
case C_up:
case C_await_up:
(*card->ch_mode) (card, 0, M_STANDBY, 1);
set_card_status (ctl, C_wont_up);
hdr->hdr_notify.ind = PH_DISCONNECT_IND;
break;
case C_wont_down:
set_card_status (ctl, C_down);
/* FALL THRU */
case C_down:
hdr->hdr_notify.ind = PH_DISCONNECT_IND;
break;
case C_wont_up:
freemsg(mb);
return;
}
} else if (state == 0) { /* Card is down */
switch (ctl->status) {
case C_lock_up:
case C_await_up: /* Might be a delayed response from taking it
* down. Do nothing for now. */
case C_down:
freemsg (mb);
return;
case C_await_back_up:
set_card_status (ctl, C_down);
if(D_L1_up(ctl) >= 0) {
freemsg (mb);
return;
} /* else FALL THRU */
case C_await_down:
hdr->hdr_notify.ind = PH_DEACTIVATE_CONF;
set_card_status (ctl, C_down);
break;
case C_up:
(*card->ch_mode) (card, 0, M_STANDBY, 1);
/* FALL THRU */
case C_wont_down:
set_card_status (ctl, C_down);
/* FALL THRU */
case C_wont_up:
hdr->hdr_notify.ind = PH_DEACTIVATE_IND;
break;
}
} else {
switch (ctl->status) {
case C_up:
freemsg (mb);
return;
case C_lock_up:
set_card_status (ctl, C_up);
hdr->hdr_notify.ind = PH_ACTIVATE_IND;
break;
case C_await_up:
set_card_status (ctl, C_up);
(*card->ch_mode) (card, 0, M_ON, 0);
hdr->hdr_notify.ind = PH_ACTIVATE_CONF;
if(ctl->offline && !isdn2_notsent)
isdn2_sendcard(ctl);
break;
case C_wont_down:
freemsg (mb);
mb = NULL;
break;
case C_down:
if(ctl->offline && !isdn2_notsent)
isdn2_sendcard(ctl);
/* FALL THRU */
case C_await_back_up:
case C_await_down: /* Oops, bus doesn't want to go down.
* Continue to listen for incoming frames. */
if(ctl->card->modes & CHM_INTELLIGENT)
set_card_status (ctl, C_up);
else
set_card_status (ctl, C_wont_down);
/* (*card->ch_mode) (card, 0, M_ON, 1); */
hdr->hdr_notify.ind = PH_ACTIVATE_NOTE;
break;
case C_wont_up:
if(!isdn2_notsent)
isdn2_sendcard(ctl);
set_card_status (ctl, C_up);
hdr->hdr_notify.ind = PH_ACTIVATE_IND;
break;
}
}
if(mb != NULL) {
D_kill_all (ctl, hdr->hdr_notify.ind);
hdr->hdr_notify.add = 0;
if (isdn_chan.qptr != NULL) {
qenable (WR (isdn_chan.qptr));
if(isdn2_debug & 0x2000) logh_printmsg (NULL, "Up", mb);
if(canput(isdn_chan.qptr->q_next))
putnext (isdn_chan.qptr, mb);
else
freemsg(mb);
D_checkactive (ctl);
} else
freemsg (mb);
}
return /* 0 */ ;
}
static int
do_chprot (isdn2_card ctl, short channel, mblk_t * proto, int flags)
{
int err = 0;
if (isdn2_debug & 0x4)
printf ("%sdo_chprot %d %d 0%o: %p %d %p\n",KERN_DEBUG, ctl ? ctl->nr : -1, channel, flags,
ctl, channel, isdn_chan.qptr);
if (ctl == NULL || (channel == 0 && isdn_chan.qptr == NULL))
return -ENXIO;
if(flags & CHP_TOCARD) {
flags &=~ CHP_TOCARD;
if((ctl->card != NULL) && (ctl->card->ch_prot != NULL))
return (*ctl->card->ch_prot)(ctl->card,channel,proto,flags);
}
if(flags & CHP_MODLIST) {
isdn2_chan ch = ctl->chan[channel];
if (ch == NULL || ch->qptr == NULL)
return -ENXIO;
if((flags & (PUSH_BEFORE|PUSH_UPDATE)) == PUSH_BEFORE)
poplist (ch->qptr, PUSH_BEFORE);
if(!(flags & PUSH_UPDATE))
err = pushlist (ch->qptr, proto, flags);
if(err == 0)
freemsg(proto);
return err;
} else if(flags & CHP_FROMSTACK) { /* to the master */
isdn23_hdr hdr;
mblk_t *mb;
mb = allocb (sizeof (struct _isdn23_hdr), BPRI_HI);
if (mb == NULL) {
if (isdn2_debug & 0x14)
printf ("%sisdn2_chprot for %d: No rawhdr mem\n",KERN_DEBUG, ctl->nr);
return -ENOMEM;
}
hdr = ((isdn23_hdr) mb->b_wptr)++;
hdr->key = HDR_PROTOCMD;
hdr->seqnum = hdrseq; hdrseq += 2;
if (channel == 0) /* D channel is always ready... */
hdr->hdr_protocmd.minor = 0;
else {
isdn2_chan ch = ctl->chan[channel];
if (ch == NULL || ch->qptr == NULL)
hdr->hdr_protocmd.minor = 0;
else
hdr->hdr_protocmd.minor = ch->dev;
}
hdr->hdr_protocmd.card = ctl->nr;
hdr->hdr_protocmd.channel = channel;
hdr->hdr_protocmd.len = dsize (proto);
DATA_TYPE(proto) = MSG_DATA;
linkb (mb, proto);
if (isdn_chan.qptr != NULL) {
if(isdn2_debug & 0x2000) logh_printmsg (NULL, "Up", mb);
if(canput(isdn_chan.qptr->q_next)) {
putnext (isdn_chan.qptr, mb);
err = 0;
} else {
if(isdn2_debug & 0x4)
printf("%sdo_chprot: MasterUpqueue full\n",KERN_DEBUG);
freeb(mb);
err = -ENXIO;
}
} else
err = -EAGAIN;
return err;
} else { /* to the stack */
isdn2_chan ch = ctl->chan[channel];
if (ch == NULL || ch->qptr == NULL) {
if(isdn2_debug & 0x14)printf ("%sisdn2_chprot for %d: No qptr\n",KERN_DEBUG, ctl->nr);
return -ENXIO;
}
DATA_TYPE(proto) = MSG_PROTO;
putq (ch->qptr, proto);
return 0;
}
}
/* --> isdn_12.h */
extern int
isdn2_chprot (struct _isdn1_card *card, short channel, mblk_t * proto, int flags)
{
isdn2_card ctl;
ctl = (isdn2_card) card->ctl;
if (ctl == NULL || (channel == 0 && isdn_chan.qptr == NULL))
return -ENXIO;
return do_chprot(ctl,channel,proto,flags &~ CHP_TOCARD /* precaution against loops */ );
}
/* --> isdn_12.h */
int
isdn2_canrecv (struct _isdn1_card *card, short channel)
{
isdn2_card ctl;
ctl = (isdn2_card) card->ctl;
if (ctl == NULL)
return 1; /* will get flushed in isdn2_recv(); avoid
* clogging the card here */
else if (channel == 0) { /* D channel is always ready... */
if(isdn_chan.qptr == NULL)
return 0;
return canput(isdn_chan.qptr->q_next);
/* XXX: For dumb cards, I should ask X.75, but at this point I
don't know the SAPI. */
} else {
isdn2_chan ch = ctl->chan[channel];
if (ch == NULL || ch->qptr == NULL)
return 1; /* avoid clogging the card; will get flushed
* in isdn2_recv() */
return canput (ch->qptr);
}
}
/* --> isdn_12.h */
int
isdn2_recv (struct _isdn1_card *card, short channel, mblk_t * data)
{
int err = 0;
isdn2_card ctl;
uchar_t ch;
#ifdef CONFIG_DEBUG_STREAMS
if(msgdsize(data) < 0)
return 0;
#endif
ctl = (isdn2_card) card->ctl;
if (ctl == NULL || (channel == 0 && isdn_chan.qptr == NULL)) {
return -ENXIO;
} else if (channel == 0) { /* D Channel */
uchar_t SAPI, TEI, x1, x2;
char cmd;
isdn2_state state;
#ifdef CONFIG_DEBUG_STREAMS
if(msgdsize(data) < 0)
return 0;
#endif
if(isdn2_log & 0x10) {
printf ("%s*** %d", KERN_DEBUG,ctl->nr);
log_printmsg (NULL, " Recv", data, KERN_DEBUG);
}
(void)msgdsize(data);
if (card->modes & CHM_INTELLIGENT) {
state = ctl->state[0];
if(state != NULL)
err = D_recv(state,0,data);
else
err = -ENXIO;
} else {
if(ctl->flags & HDR_CARD_DEBUG) {
isdn23_hdr hdr;
mblk_t *m1 = allocb(sizeof(*hdr),BPRI_MED);
mblk_t *m2 = dupmsg(data);
if (m1 == NULL || m2 == NULL) {
if(m1 != NULL)
freemsg(m1);
if(m2 != NULL)
freemsg(m2);
} else {
hdr = ((isdn23_hdr) m1->b_wptr)++;
hdr->key = HDR_RAWDATA;
hdr->seqnum = hdrseq; hdrseq += 2;
hdr->hdr_rawdata.card = ctl->nr;
hdr->hdr_rawdata.dchan = 1;
hdr->hdr_rawdata.len = dsize (m2);
hdr->hdr_rawdata.flags = 0;
linkb (m1, m2);
if(canput(isdn_chan.qptr->q_next))
putnext (isdn_chan.qptr, m1);
else
freemsg(m1);
}
}
if (ctl->status != C_up && ctl->status != C_wont_down) {
if(isdn2_debug & 0x80)
printf("%s -- L1 up\n",KERN_DEBUG);
(void) D_L1_up (ctl);
}
(void)msgdsize(data);
data = pullupm (data, 0);
if (data == NULL) /* Packet too short */
return 0;
x1 = SAPI = *data->b_rptr++;
if (SAPI & 0x01) { /* TODO: X25 packet? */
if (isdn2_debug & 0x10)
printf ("%sisdn2_recv %d: SAPI %x invalid\n",KERN_DEBUG, ctl->nr, SAPI);
freemsg (data);
return 0 /* ESRCH */ ;
}
data = pullupm (data, 0);
if (data == NULL)
return 0;
x2 = TEI = *data->b_rptr++;
if ((TEI & 0x01) == 0) {
if (isdn2_debug & 0x10)
printf ("%sisdn2_recv %d: TEI %x invalid\n",KERN_DEBUG, ctl->nr, TEI);
goto rawdata;
}
cmd = (SAPI & 0x02) ? 1 : 0;
SAPI >>= 2;
TEI >>= 1;
for(ch=0;ch <= N_TEI; ch++) {
if (ctl->TEI[ch] == TEI || TEI == TEI_BROADCAST)
break;
}
if(ch > N_TEI) {
if (isdn2_debug & 0x100)
printf("%sisdn2_recv %d: %02x: not my TEI (%02x)\n",KERN_DEBUG,ctl->nr,TEI,ctl->TEI[0]);
freemsg (data);
return 0;
}
data = pullupm (data, 0);
if (data == NULL)
return 0;
state = D__findstate (ctl, SAPI,ch);
if (state != NULL) {
if (TEI == TEI_BROADCAST)
cmd |= 2;
err = x75_recv (&state->state, cmd, data);
} else if (TEI == TEI_BROADCAST && isdn_chan.qptr != NULL) {
rawdata:
err = -ENXIO;
} else {
err = 0; /* Not an error */
freemsg (data);
}
}
} else { /* B Channel */
isdn2_chan chn = ctl->chan[channel];
if (chn != NULL && chn->qptr != NULL) {
putq (chn->qptr, data);
err = 0;
} else {
err = -ENXIO;
(*card->ch_mode) (card, channel, M_FREE, 0); /* No B Channel. Take it
* down. (Needless to
* say, this shouldn't
* happen.) */
}
}
return err;
}
/* --> isdn_12.h */
int
isdn2_backenable (struct _isdn1_card *card, short channel)
{
isdn2_card ctl = (isdn2_card) card->ctl;
isdn2_chan chan;
if (ctl == NULL)
return -ENXIO;
if (isdn2_debug & 0x80)
printf ("%sisdn2_backenable %d %d\n",KERN_DEBUG, ctl->nr, channel);
if (channel > 0 && (unsigned) channel <= ctl->card->nr_chans) {
if ((chan = ctl->chan[channel]) != NULL && chan->qptr != NULL)
qenable (WR (chan->qptr));
} else if (isdn_chan.qptr != NULL) {
qenable (WR (isdn_chan.qptr));
if (channel == -1)
channel = 0; /* All channels */
else
channel = ctl->card->nr_chans+1; /* All D channels */
for (; channel <= MAXCHAN; channel++) {
if ((chan = ctl->chan[channel]) != NULL && chan->qptr != NULL)
qenable (WR (chan->qptr));
}
}
return 0;
}
/**
** ISDN driver handling
**/
int
isdn2_init (void)
{
printf ("%sISDN library present.\n Max %d channels per card, min %d D channel connections\n",KERN_DEBUG, MAXCHAN, MAX_D);
bzero (&isdn_chan, sizeof (isdn_chan));
bzero (isdnchan, sizeof (isdnchan));
isdn2_notsent = 0;
return 0;
}
/*
* Send info about this card up.
*/
static void
isdn2_sendcard (isdn2_card card)
{
isdn23_hdr hdr;
mblk_t *mb;
ushort_t i;
for(i=1; i <= card->card->nr_chans; i++)
(*card->card->ch_mode)(card->card, i, M_OFF, 0);
card->offline = 0;
if ((mb = allocb (sizeof (struct _isdn23_hdr), BPRI_HI)) == NULL) {
if (isdn2_debug & 0x10)
printf ("%sisdn2_sendcard: no memory\n",KERN_DEBUG);
return /* ENOMEM */ ;
}
hdr = ((isdn23_hdr) mb->b_wptr)++;
hdr->key = HDR_CARD;
hdr->seqnum = hdrseq; hdrseq += 2;
hdr->hdr_card.card = card->nr;
hdr->hdr_card.id = card->id;
if(card->card->nr_dchans < 2) {
hdr->hdr_card.dchans = 1;
hdr->hdr_card.bchans = card->card->nr_chans;
} else {
hdr->hdr_card.dchans = card->card->nr_dchans;
hdr->hdr_card.bchans = card->card->nr_chans / card->card->nr_dchans;
}
hdr->hdr_card.modes = card->card->modes;
if (isdn_chan.qptr != NULL) {
if(isdn2_debug & 0x2000) logh_printmsg (NULL, "Up", mb);
if(canput(isdn_chan.qptr->q_next)) {
putnext (isdn_chan.qptr, mb);
(*card->card->ch_mode) (card->card, 0, M_STANDBY, 1);
return;
}
}
freemsg (mb);
(*card->card->ch_mode) (card->card, 0, M_OFF, 0);
return /* ENXIO / ENOSPC */ ;
}
/*
* Send info about all cards up.
*/
static void
isdn2_sendcards (void *ignored)
{
isdn2_card crd;
isdn2_notsent = 0;
for (crd = isdn_card; crd != NULL; crd = crd->next) {
if (!crd->offline) {
isdn2_sendcard (crd);
}
}
return;
}
/* Streams code to open the driver. */
static int
isdn2_open (queue_t * q, dev_t dev, int flag, int sflag ERR_DECL)
{
isdn2_chan ch;
char isinit = (q->q_ptr == NULL);
if (sflag == CLONEOPEN || sflag == MODOPEN) {
#ifndef MODULE
static unsigned char nr = 0;
do { dev = ++nr; } while (minor(dev) == 0);
#else
printf ("%sisdn2_open: CLONE/MODOPEN\n",KERN_DEBUG);
ERR_RETURN(-ENXIO);
#endif
}
dev = minor (dev);
/*
* The master driver can't be opened more than once.
*/
if (dev >= NPORT) {
printf ("%sisdn2_open: dev %d > NPORT %d\n",KERN_DEBUG,dev,NPORT);
ERR_RETURN(-ENXIO);
}
if (dev == 0) {
if (isdn_chan.qptr != NULL) {
ERR_RETURN(-EBUSY);
}
ch = &isdn_chan;
} else { /* dev > 0; require a new device for O_EXCL */
if (isdn_chan.qptr == NULL) {
ERR_RETURN(-ENXIO);
}
if ((ch = (isdn2_chan)q->q_ptr) == NULL) {
#if 0
if (!(flag & O_EXCL)) {
printf ("%sisdn2_open: open must be exclusive\n",KERN_DEBUG,dev,nport);
ERR_RETURN(-ENXIO);
}
#endif
ch = malloc(sizeof(*ch));
if (ch == NULL) {
if (isdn2_debug & 0x10)
printf ("%sisdn2_open: no memory\n",KERN_DEBUG);
ERR_RETURN(-ENOMEM);
}
memset(ch,0,sizeof(*ch));
ch->dev = dev;
} else {
if((flag & O_EXCL)) {
ERR_RETURN(-EBUSY);
}
}
}
if (ch->qptr == NULL) { /* /dev/isdn -- somebody wants to open a
* connection. */
if (dev > 0) {
poplist (q, 0);
if (isdn_chan.qptr != NULL) {
isdn23_hdr hdr;
mblk_t *mb = allocb (sizeof (struct _isdn23_hdr), BPRI_MED);
if (mb != NULL) {
hdr = ((isdn23_hdr) mb->b_wptr)++;
hdr->key = HDR_OPEN;
hdr->seqnum = hdrseq; hdrseq += 2;
hdr->hdr_open.minor = dev;
hdr->hdr_open.flags = flag;
#ifdef __linux__
hdr->hdr_open.uid = (current->suid == 0) ? current->suid : current->uid;
if(0) printk("%s2_open:uid %d\n",KERN_DEBUG,hdr->hdr_open.uid);
#else
hdr->hdr_open.uid = u.u_uid;
#endif
if(isdn2_debug & 0x2000) logh_printmsg (NULL, "Up", mb);
if(canput(isdn_chan.qptr->q_next))
putnext (isdn_chan.qptr, mb);
else {
freemsg(mb);
ERR_RETURN(-ENOSPC);
}
} else {
if (isdn2_debug & 0x10)
printf ("%sisdn2_open %d: Can't notify controller: no mem\n",KERN_DEBUG, dev);
ERR_RETURN(-ENOMEM);
}
}
}
ch->qptr = q;
ch->oflag = flag;
if (dev == 0)
ch->status = M_D_ctl;
else {
ch->status = M_free;
isdnchan[dev] = ch;
}
}
WR (q)->q_ptr = (caddr_t) ch;
q->q_ptr = (caddr_t) ch;
if (isinit && (dev == 0)) { /* /dev/isdnmaster */
isdn2_card crd;
for (crd = isdn_card; crd != NULL; crd = crd->next) {
int j;
for (j=0; j <= N_TEI; j++)
crd->TEI[j] = TEI_BROADCAST;
}
isdn2_notsent = 1;
#ifdef NEW_TIMEOUT
timer_sendcards =
#endif
timeout (isdn2_sendcards, NULL, HZ * 2);
}
if (isdn2_debug & 0x10)
printf ("%sISDN %d open (%p)\n",KERN_DEBUG, dev, q);
MORE_USE;
return dev;
}
/*
* Send this status message upstream to a device.
*/
#if 0 /* not needed right now */
static void
putproto (SUBDEV minor, ushort_t inf)
{
queue_t *q;
mblk_t *mb;
if (isdn2_debug & 0x100)
printf ("%sputproto %d %d\n",KERN_DEBUG, minor, inf);
if (minor >= NPORT)
return;
else if (isdnchan[minor] == NULL || (q = isdnchan[minor]->qptr) == NULL)
return;
if ((mb = allocb (3, BPRI_HI)) == NULL)
return;
m_putid (mb, inf);
DATA_TYPE(mb) = MSG_PROTO;
putnext (q, mb);
}
#endif
/*
* Take down a connection.
*/
static int
isdn2_disconnect (isdn2_chan ch, uchar_t error)
{
int ms = splstr ();
if (isdn2_debug & 0x100) {
printf ("%sisdn2_disconnect %p %d\n",KERN_DEBUG, ch, error);
if(ch->card != NULL)
printf ("%sDisconnect dev %d card %d chan %d\n",KERN_DEBUG, ch->dev, ch->card->nr, ch->channel);
}
if (ch->status != M_free && (ch->channel > MAXCHAN)) {
splx (ms);
printf ("%sSevere problem: isdn2_disconnect: Channel %d !?!\n",KERN_DEBUG, ch->channel);
return -EFAULT;
}
switch (ch->status) {
case M_B_conn:
{
struct _isdn1_card *chx;
if (ch->card != NULL && (chx = ch->card->card) != NULL)
(*chx->ch_mode) (chx, ch->channel, M_FREE, 0);
}
/* FALL THRU */
case M_D_conn:
if (ch->card != NULL) {
if (ch->card->chan[ch->channel] != ch) {
isdn2_chan cho;
printf ("%s*** Chan ptr in disconnect bad! dev %d card %d chan %d points to ",KERN_DEBUG, ch->dev, ch->card->nr, ch->channel);
if((cho = ch->card->chan[ch->channel]) != NULL)
printf ("dev %d, card %d chan %d\n", cho->dev, cho->card->nr, cho->channel);
else
printf("NULL\n");
} else
ch->card->chan[ch->channel] = NULL;
}
/* FALL THRU */
case M_free:
{
/* putproto (ch ->dev, PROTO_DISCONNECT); */
/* ch->chan = NULL; */
ch->card = NULL;
ch->status = M_free;
if (isdn_chan.qptr != NULL && error != 0xFF) {
isdn23_hdr hdr;
mblk_t *mb = allocb (sizeof (struct _isdn23_hdr), BPRI_MED);
if (mb != NULL) {
hdr = ((isdn23_hdr) mb->b_wptr)++;
hdr->key = HDR_DETACH;
hdr->seqnum = hdrseq; hdrseq += 2;
hdr->hdr_detach.connref = ch->connref;
hdr->hdr_detach.minor = ch->dev;
hdr->hdr_detach.error = error;
hdr->hdr_detach.perm = 0;
if(isdn2_debug & 0x2000) logh_printmsg (NULL, "Up", mb);
if(canput(isdn_chan.qptr->q_next))
putnext (isdn_chan.qptr, mb);
else
freemsg(mb);
} else {
if (isdn2_debug & 0x10)
printf ("%sisdn2_disconnect %d: Can't notify controller: no mem\n",KERN_DEBUG, ch->dev);
}
}
}
break;
case M_D_ctl:
{
int i;
queue_t *q;
isdn2_card crd;
for (crd = isdn_card; crd != NULL; crd = crd->next) {
D_kill_all (crd, 0);
D_L1_down (crd);
}
for (i = 1; i < NPORT; i++)
if ((isdnchan[i] != NULL) && ((q = isdnchan[i]->qptr) != NULL)) {
if (isdn2_debug & 0x10)
printf ("%sHang 2\n",KERN_DEBUG);
putctlx (q, M_HANGUP);
}
if (isdn2_notsent) {
#ifdef OLD_TIMEOUT
untimeout (isdn2_sendcards, NULL);
#else
untimeout (timer_sendcards);
#endif
}
}
break;
default:;
}
ch->connref = 0;
ch->status = M_free;
splx (ms);
return 0;
}
static void
isdn2_unblock (isdn2_chan ch)
{
if (ch->status == M_blocked)
ch->status = M_free;
return;
}
/* Streams code to close the driver. */
static void
isdn2_close (queue_t *q, int dummy)
{
isdn2_chan ch = (isdn2_chan) q->q_ptr;
int ms = splstr ();
ch->qptr = NULL;
if (isdn2_debug & 0x10)
printf ("%sISDN %d: Closed.\n",KERN_DEBUG, ch->dev);
switch (ch->status) {
case M_D_ctl:
case M_B_conn:
case M_D_conn:
isdn2_disconnect (ch, 0);
break;
default:;
}
if (isdn_chan.qptr != NULL) {
isdn23_hdr hdr;
mblk_t *mb = allocb (sizeof (struct _isdn23_hdr), BPRI_MED);
if (mb != NULL) {
hdr = ((isdn23_hdr) mb->b_wptr)++;
hdr->key = HDR_CLOSE;
hdr->seqnum = hdrseq; hdrseq += 2;
hdr->hdr_close.minor = ch->dev;
hdr->hdr_close.error = 0;
if(isdn2_debug & 0x2000) logh_printmsg (NULL, "Up", mb);
if(canput(isdn_chan.qptr->q_next))
putnext (isdn_chan.qptr, mb);
else
freemsg(mb);
} else if (isdn2_debug & 0x10)
printf ("%sisdn2_close %d: Can't notify controller: no mem\n",KERN_DEBUG, ch->dev);
ch->status = M_blocked;
#ifdef NEW_TIMEOUT
ch->timer_unblock =
#endif
timeout ((void *)isdn2_unblock, ch, HZ * 10);
} else
ch->status = M_free;
if (ch->dev > 0)
isdnchan[ch->dev] = NULL;
splx (ms);
LESS_USE;
return;
}
#ifdef __linux__
#define c_setq setq
#else
/*
* Set up a Streams queue.
*
* This code shamelessly stolen from Sys5R3.
*/
static void
c_setq (queue_t * rq, struct qinit *rinit, struct qinit *winit)
{
queue_t *wq = WR (rq);
rq->q_qinfo = rinit;
rq->q_hiwat = rinit->qi_minfo->mi_hiwat;
rq->q_lowat = rinit->qi_minfo->mi_lowat;
rq->q_minpsz = rinit->qi_minfo->mi_minpsz;
rq->q_maxpsz = rinit->qi_minfo->mi_maxpsz;
wq->q_qinfo = winit;
wq->q_hiwat = winit->qi_minfo->mi_hiwat;
wq->q_lowat = winit->qi_minfo->mi_lowat;
wq->q_minpsz = winit->qi_minfo->mi_minpsz;
wq->q_maxpsz = winit->qi_minfo->mi_maxpsz;
}
#endif
/*
* Attach a module to a Streams queue.
*
*/
static int
c_qattach (struct streamtab *qinfo, queue_t * qp, int flag)
{
queue_t *rq;
long s;
int sflg;
int err;
if (!(rq = allocq ())){
printf (" :allocq");
return (0);
}
sflg = 0;
s = splstr ();
rq->q_next = qp;
WR (rq)->q_next = WR (qp)->q_next;
if (WR (qp)->q_next) {
OTHERQ (WR (qp)->q_next)->q_next = rq;
sflg = MODOPEN;
}
WR (qp)->q_next = WR (rq);
c_setq (rq, qinfo->st_rdinit, qinfo->st_wrinit);
rq->q_flag |= QWANTR;
WR (rq)->q_flag |= QWANTR;
if ((err = (*rq->q_qinfo->qi_qopen) (rq, 0, flag, sflg)) < 0) {
printf ("%s :No Open %d %p",KERN_DEBUG, err, rq->q_qinfo->qi_qopen);
qdetach (rq, 0, 0);
splx (s);
return err;
}
splx (s);
return 0;
}
/*
* Pop all modules off a queue.
*
* Push the modules named in the mblk onto the queue.
*
* Warning -- these modules must not sleep.
*/
static int
pushlist (queue_t * q, mblk_t * mp, char flags)
{
int ms = splstr ();
queue_t *xq;
int err;
#ifdef CONFIG_DEBUG_STREAMS
if(msgdsize(mp) < 0)
return 0;
#endif
if (isdn2_debug & 0x20)
printf ("%sQ Push %p %p 0%o: ",KERN_DEBUG, q, mp, flags);
xq = q->q_next; /* for qattach */
while (mp->b_rptr < mp->b_wptr) {
if(isdn2_debug & 0x20)printf (" ");
while (mp->b_rptr < mp->b_wptr) {
if (*mp->b_rptr <= ' ')
mp->b_rptr++;
else
break;
}
if (mp->b_rptr < mp->b_wptr) {
streamchar chx, *ch1 = mp->b_rptr, *ch2 = ch1;
struct fmodsw *fm;
while(ch2 < mp->b_wptr && *ch2 > ' ')
ch2++;
chx = *ch2; *ch2 = '\0';
if(flags & PUSH_AFTER) {
if(!strcmp(ch1,"reconn")) {
if(isdn2_debug & 0x20) printf(" <skip head>");
flags &=~ PUSH_AFTER;
} else
goto nx;
} else if(flags & PUSH_BEFORE) {
if(!strcmp(ch1,"reconn")) {
*ch2 = chx;
if(isdn2_debug & 0x20) printf(" <skip rest>");
goto fin;
}
}
if(strcmp(ch1,"-")) {
for (fm = fmod_sw; fm < &fmod_sw[fmodcnt]; fm++) {
if (fm->f_str == NULL)
continue;
if(!strcmp(ch1,fm->f_name))
goto found;
}
printf ("%sQ_Push: %s -- not found\n", KERN_ERR,ch1);
*ch2 = chx;
return -ENOENT;
found:
if(isdn2_debug & 0x20)printf (" %s", fm->f_name);
if ((err = c_qattach (fm->f_str, xq, 0)) < 0) {
*ch2 = chx;
splx (ms);
printf ("%sQ_Push: %s -- can't attach\n", KERN_WARNING,fm->f_name);
return err;
}
}
nx:
*ch2 = chx;
mp->b_rptr = ch2;
}
}
fin:
splx (ms);
if(flags & PUSH_AFTER) if(isdn2_debug & 0x20) printf(" <skipped all>");
if(isdn2_debug & 0x20)printf ("\n");
return 0;
}
static void
poplist (queue_t * q, char flags)
{
if (q == NULL || q->q_next == NULL) {
printf ("%sErr PopList NULL! %p\n",KERN_DEBUG, q);
return;
}
while (q->q_next->q_next) {
char *n = q->q_next->q_qinfo->qi_minfo->mi_idname;
if(flags & PUSH_BEFORE)
if (!strcmp(n,"reconn"))
break;
if (!strcmp(n,"proto"))
break;
qdetach (q->q_next, 1, 0);
}
if (!(flags & PUSH_BEFORE)) {
mblk_t *mb;
if ((mb = allocb (32, BPRI_MED)) != NULL) {
if (isdn2_log & 4)
m_putsz(mb,"strlog");
m_putsz(mb,"proto");
if (isdn2_log & 1)
m_putsz(mb,"strlog");
if (isdn2_log & 2)
m_putsz(mb,"qinfo");
pushlist (q, mb, flags);
freeb (mb);
}
else printf("%sPOPLIST: could not alloc\n",KERN_DEBUG);
}
}
/* Streams code to write data. */
static void
isdn2_wput (queue_t *q, mblk_t *mp)
{
isdn2_chan ch = (isdn2_chan) q->q_ptr;
#ifdef CONFIG_DEBUG_STREAMS
if(msgdsize(mp) < 0)
return;
#endif
if (isdn2_debug & 0x100)
printf ("%sisdn2_wput %p.%p.%p %d of %d\n",KERN_DEBUG, mp,DATA_BLOCK(mp),mp->b_cont, msgdsize(mp),DATA_TYPE(mp));
switch (DATA_TYPE(mp)) {
case M_IOCTL:
DATA_TYPE(mp) = M_IOCNAK;
((struct iocblk *)mp->b_rptr)->ioc_error =
#ifdef linux
ENOIOCTLCMD
#else
EINVAL
#endif
;
qreply (q, mp);
break;
case CASE_DATA:
mp = pullupm (mp, 1);
if ((ch == &isdn_chan) && ((isdn23_hdr) mp->b_rptr)->key != HDR_DATA)
DATA_TYPE(mp) = MSG_DATA;
putq (q, mp);
break;
case MSG_PROTO:
putq (q, mp);
break;
case M_FLUSH:
if(ch->status == M_D_ctl)
sysdump("FLUSH wq",NULL,0);
if (*mp->b_rptr & FLUSHW) {
isdn2_chan chan = (isdn2_chan) q->q_ptr;
struct _isdn1_card *crd1;
flushq (q, 0);
if (chan->status == M_B_conn && chan->card != NULL && (crd1 = chan->card->card) != NULL) {
(*crd1->flush) (crd1, chan->channel);
}
}
if (*mp->b_rptr & FLUSHR) {
flushq (RD (q), 0);
*mp->b_rptr &= ~FLUSHW;
qreply (q, mp);
} else
freemsg (mp);
break;
default:{
log_printmsg (NULL, "Strange ISDN", mp, KERN_WARNING);
/* putctlerr(RD(q)->b_next, -ENXIO); */
freemsg (mp);
break;
}
}
return;
}
/*
* If there was an error, send back the header as invalid.
*/
#ifdef CONFIG_DEBUG_ISDN
#define h_reply(a,b,c) deb_h_reply(__LINE__,a,b,c)
static int
deb_h_reply (unsigned int deb_line, queue_t * q, isdn23_hdr hdr, short err)
#else
static int
h_reply (queue_t * q, isdn23_hdr hdr, short err)
#endif
{
isdn23_hdr hd;
mblk_t *mb;
#if 0
if (err == 0)
return 0;
#endif
if(hdr->key & HDR_NOERROR)
return 0;
if (isdn2_debug & 0x100)
printf ("%sh_reply %p %p %d\n",KERN_DEBUG, q, hdr, err);
if ((mb = allocb (2 * sizeof (struct _isdn23_hdr), BPRI_HI)) == NULL) {
if (isdn2_debug & 0x10)
printf ("%sh_reply: no memory\n",KERN_DEBUG);
return -ENOMEM;
}
hd = ((isdn23_hdr) mb->b_wptr)++;
hd->key = HDR_INVAL;
hd->seqnum = hdrseq; hdrseq += 2;
if(err < 0)
err = -err;
hd->hdr_inval.error = err;
*((isdn23_hdr) mb->b_wptr)++ = *hdr;
if (!(q->q_flag & QREADR))
q = RD (q);
#ifdef CONFIG_DEBUG_ISDN
if(isdn2_debug & 0x2000) logh__printmsg (deb_line,NULL, "Up", mb);
#else
if(isdn2_debug & 0x2000) logh_printmsg (NULL, "Up", mb);
#endif
putnext (q, mb);
return 0;
}
/* Streams code to scan the write queue. */
static void
isdn2_wsrv (queue_t *q)
{
mblk_t *mp;
while ((mp = getq (q)) != NULL) {
mblk_t *mp2;
isdn2_chan chan = (isdn2_chan) q->q_ptr;
struct _isdn23_hdr hdr;
int err;
isdn2_state state;
isdn2_card crd;
/*
* This collects the appropriate amout of characters as told by the header.
*
* Actually, we don't collect anything; the stuff is just discarded.
*/
#define XLENHDR(_len) do { \
if(dsize(mp) < _len) { \
freemsg(mp); \
printf("%s -- dsize %d, len %d\n",KERN_DEBUG,dsize(mp),_len); \
h_reply(q,&hdr,EIO); \
mp = NULL; goto free_it; \
}; \
if(_len > 0) \
mp = pullupm(mp,1); \
} while(0) /**/
#define LENHDR(_who) XLENHDR(hdr.hdr_##_who.len)
#define NOLENHDR() do { \
mp = pullupm(mp,0); \
} while(0) /**/
/* Get the card pointer off the header */
#define CARD(_who) do { int i = hdr.hdr_##_who.card; \
for(crd = isdn_card; crd != NULL; crd = crd->next) \
if (crd->nr == i) break; \
if(crd == NULL) { \
if(isdn2_debug&1)printf("%s -- Card %d\n",KERN_DEBUG,i); \
h_reply(q,&hdr,ENXIO); goto free_it; } \
} while(0) /**/
/* Get the minor number */
#define xMINOR(_who) do { \
minor = hdr.hdr_##_who.minor; \
if ((minor < 1) || (minor >= NPORT) || \
((chan = isdnchan[minor]) == NULL) || (chan->qptr) == NULL) { \
if(isdn2_debug&1)printf("%s -- Minor %d\n",KERN_DEBUG,minor); \
h_reply (q, &hdr, ENXIO); goto free_it; } \
} while(0) /**/
if (isdn2_debug & 0x8)
printf ("%swsrv %p.%p.%p\n",KERN_DEBUG, mp, DATA_BLOCK(mp), mp->b_cont);
if(q == WR(isdn_chan.qptr))
if(isdn2_debug & 0x2000) logh_printmsg (NULL, "Down", mp);
switch (DATA_TYPE(mp)) {
default:
freemsg (mp);
break;
case MSG_PROTO:
{
/* status == M_D_conn */
isdn23_hdr hdr2;
#if 0
switch (*(ushort_t *) mp->b_rptr) {
case PROTO_DISCONNECT:
{
mblk_t *mz = copymsg (mp);
if (mz != NULL)
qreply (q, mz);
}
break;
}
#endif
{
if (chan->card != NULL) {
if((err = do_chprot(chan->card,chan->channel,mp,CHP_FROMSTACK|CHP_TOCARD)) < 0) {
printf("%sChProtErr isdn_2.c %d %d\n",KERN_DEBUG,__LINE__,err);
freemsg(mp);
/* TODO: Kill me. */
}
} else {
mblk_t *mb = allocb (sizeof (struct _isdn23_hdr), BPRI_MED);
if (mb == NULL) {
printf("%sNoMemHdr isdn_2.c %d\n",KERN_DEBUG,__LINE__);
putbqf (q, mp);
return;
}
if(isdn2_debug & 0x10)
printf("%sMsgProt NoCard %d isdn_2.c %d\n",KERN_DEBUG,chan->dev,__LINE__);
hdr2 = ((isdn23_hdr) mb->b_wptr)++;
hdr2->key = HDR_PROTOCMD;
hdr2->seqnum = hdrseq; hdrseq += 2;
hdr2->hdr_protocmd.minor = chan->dev;
hdr2->hdr_protocmd.card = 0;
hdr2->hdr_protocmd.channel = 0;
hdr2->hdr_protocmd.len = dsize (mp);
linkb (mb, mp);
do {
DATA_TYPE(mp) = M_DATA;
mp = mp->b_cont;
} while(mp != NULL);
if (isdn_chan.qptr != NULL) {
if(isdn2_debug & 0x2000) logh_printmsg (NULL, "Up", mb);
if(canput(isdn_chan.qptr->q_next)) {
putnext (isdn_chan.qptr, mb);
} else {
freemsg(mb);
}
} else {
freemsg (mb);
printf ("%sHang 4\n",KERN_DEBUG);
putctlx (RD (q), M_HANGUP);
}
}
}
}
break;
case CASE_DATA:
{
mp = pullupm (mp, 0);
if (mp != NULL) {
SUBDEV minor;
DATA_TYPE(mp) = M_DATA;
switch (chan->status) {
default:
{
freemsg (mp);
mp = NULL;
if (isdn2_debug & 0x10)
printf ("%sISDN %d: Msg arrived for status %d\n",KERN_DEBUG, chan->dev, chan->status);
}
break; /* message deleted below */
case M_D_ctl:
{
mp2 = mp;
mp = pullupm (mp, sizeof (struct _isdn23_hdr));
if (mp == NULL) { /* Not a good message..? */
if(isdn2_debug&0x200) printk(".NullCtl.");
freemsg (mp2);
break;
}
hdr = *((isdn23_hdr) mp->b_rptr)++;
if (mp->b_rptr > mp->b_wptr) {
if(isdn2_debug&0x200) printk(".OverMsg.");
freemsg (mp);
mp = NULL;
break;
}
if(isdn2_debug & 0x100)
printf("%sDispatch %x\n",KERN_DEBUG,hdr.key);
switch (hdr.key & ~HDR_FLAGS) {
default:
if (isdn2_debug & 0x100)
printf ("%sunknown key %d\n",KERN_DEBUG, hdr.key);
h_reply (q, &hdr, EINVAL);
break;
#if 0
{ /* redo */
mblk_t *mz = allocb (sizeof (struct _isdn23_hdr), BPRI_MED);
if (mz == NULL) {
printf("%sFreeReturn\n",KERN_DEBUG);
freemsg (mp);
return;
}
*((isdn23_hdr) mz->b_wptr)++ = hdr;
if (mp != NULL) {
linkb (mz, mp);
DATA_TYPE(mz) = DATA_TYPE(mp);
mp = NULL;
}
putbqf (q, mz);
}
return;
#endif
case HDR_ATCMD:
{
mblk_t *mz = NULL;
LENHDR (atcmd);
xMINOR (atcmd);
mz = allocb (4, BPRI_MED);
if (mz != NULL) {
m_putid (mz, PROTO_AT);
DATA_TYPE(mz) = MSG_PROTO;
linkb (mz, mp);
} else
freemsg (mp);
mp = NULL;
}
break;
case HDR_PROTOCMD:
{
streamchar *oldhd;
ushort_t id, xid;
int minor;
long ismodlist;
LENHDR (protocmd);
oldhd = mp->b_rptr;
if ((err = m_getid(mp,&id)) != 0) {
h_reply (q, &hdr, err);
break;
}
ismodlist = (id == PROTO_MODLIST);
minor = hdr.hdr_protocmd.minor;
if (isdn2_debug & 0x10)
printk("%sMinorSet %d -> %d %d\n",KERN_DEBUG,minor,(isdnchan[minor]&&isdnchan[minor]->card)?isdnchan[minor]->card->nr:-1,isdnchan[minor]?isdnchan[minor]->channel:-1);
if ((minor != 0) && (isdnchan[minor] != NULL) && (isdnchan[minor]->card != NULL)) {
/* This is a temporary kludge */
hdr.hdr_protocmd.card = isdnchan[minor]->card->nr;
hdr.hdr_protocmd.channel = isdnchan[minor]->channel;
hdr.hdr_protocmd.minor = 0;
}
if(ismodlist) {
if((err = m_geti(mp,&ismodlist)) != 0) {
h_reply (q, &hdr, err);
break;
}
ismodlist |= CHP_MODLIST;
while(m_getsx(mp,&xid) == 0) ;
} else
mp->b_rptr = oldhd;
if (hdr.hdr_protocmd.minor == 0) {
CARD (protocmd);
if (hdr.hdr_protocmd.channel > crd->card->nr_chans) {
printf ("%s -- bad channel\n",KERN_DEBUG);
hdr.hdr_protocmd.minor = minor;
h_reply (q, &hdr, -EINVAL);
break;
}
if (chan->card != NULL && chan->card->card != NULL)
qenable(WR(chan->qptr));
if((err = do_chprot(crd,hdr.hdr_protocmd.channel,mp,CHP_TOCARD|ismodlist)) < 0) {
printf ("%s -- Err SetMode %d\n",KERN_DEBUG,err);
hdr.hdr_protocmd.minor = minor;
} else {
mp = NULL;
}
h_reply (q, &hdr, err);
break;
}
xMINOR (protocmd);
if(ismodlist) {
if(!(ismodlist & PUSH_UPDATE))
err = pushlist(chan->qptr,mp,ismodlist);
else
err = 0;
} else {
oldhd = mp->b_rptr;
DATA_TYPE(mp) = MSG_PROTO;
if(canput(chan->qptr->q_next)) {
putnext(chan->qptr,mp);
mp = NULL;
err = 0;
} else
err = -ENOSPC;
}
h_reply (q, &hdr, err);
}
break;
case HDR_XDATA:
{
LENHDR (xdata);
xMINOR (xdata);
putnext (chan->qptr, mp);
mp = NULL;
break;
}
break;
case HDR_UIDATA:
{
LENHDR (uidata);
CARD (uidata);
#ifdef DO_MULTI_TEI
state = D__findstate (crd, hdr.hdr_uidata.SAPI,hdr-hdr_uidata.bchan);
#else
state = D__findstate (crd, hdr.hdr_uidata.SAPI,0);
#endif
if (state == NULL || state->state.status == S_free) {
h_reply (q, &hdr, EINVAL);
break;
}
if (!((crd->card->modes & CHM_INTELLIGENT)
? D_cansend(state)
: x75_cansend (&state->state, 1))) {
if (isdn2_debug & 0x10)
printf ("%shdr_uidata: cannot send\n",KERN_DEBUG);
h_reply (q, &hdr, (crd->status == C_wont_up) ? EIO : ENOMEM);
break;
}
DATA_TYPE(mp) = M_DATA;
if (crd->card->modes & CHM_INTELLIGENT)
err = D_send (state, hdr.hdr_uidata.broadcast, mp);
else
err = x75_send (&state->state, hdr.hdr_uidata.broadcast ? 3 : 1, mp);
if (err != 0) {
h_reply (q, &hdr, err);
} else
mp = NULL;
}
break;
case HDR_DATA:
{
LENHDR (data);
CARD (data);
#ifdef DO_MULTI_TEI
state = D__findstate (crd, hdr.hdr_data.SAPI,hdr.hdr_data.bchan);
#else
state = D__findstate (crd, hdr.hdr_data.SAPI,0);
#endif
if (state == NULL) {
h_reply (q, &hdr, EINVAL);
break;
}
if (!((crd->card->modes & CHM_INTELLIGENT)
? D_cansend(state)
: x75_cansend (&state->state, 0))) {
if (isdn2_debug & 0x10)
printf ("%shdr_data: cannot send\n",KERN_DEBUG);
h_reply (q, &hdr, (crd->status == C_wont_up) ? EIO : ENOMEM);
break;
}
DATA_TYPE(mp) = M_DATA;
if (crd->card->modes & CHM_INTELLIGENT)
err = D_send(state,0,mp);
else
err = x75_send (&state->state, 0, mp);
if (err != 0)
h_reply (q, &hdr, err);
else
mp = NULL;
}
break;
case HDR_RAWDATA:
{
LENHDR (rawdata);
CARD (rawdata);
if ((err = (*crd->card->send) (crd->card, 0, mp)) != 0) {
h_reply (q, &hdr, err);
} else
mp = NULL;
break;
}
break;
case HDR_CLOSE:
{
queue_t *qq;
NOLENHDR ();
xMINOR (close);
isdn2_disconnect (chan, hdr.hdr_close.error);
if ((isdnchan[minor] != NULL) && ((qq = isdnchan[minor]->qptr) != NULL)) {
if (hdr.hdr_close.error != 0)
putctlerr (qq, hdr.hdr_close.error);
else
putctlx (qq, M_HANGUP);
} else {
if(isdn2_debug&1)printf("%s-- not open\n",KERN_DEBUG);
h_reply (q, &hdr, ENXIO);
}
}
break;
case HDR_ATTACH:
{
int ms;
NOLENHDR ();
xMINOR (attach);
CARD (attach);
if (isdn2_debug & 0x10)
printf ("%sAttach card %d channel %d to minor %d connref %ld %s%s\n",KERN_DEBUG,
hdr.hdr_attach.card, hdr.hdr_attach.chan, minor, hdr.hdr_attach.connref,
(hdr.hdr_attach.listen & 2) ? "setup" : ((hdr.hdr_attach.listen & 1) ? "listen" : "talk"),
(hdr.hdr_attach.listen & 4) ? " force" : "");
ms = splstr ();
if (chan->card != NULL && chan->card != crd) {
printf ("%s -- minor not free\n",KERN_DEBUG);
h_reply (q, &hdr, EBUSY);
splx (ms);
break;
} else if (hdr.hdr_attach.chan > crd->card->nr_chans) {
printf ("%s -- bad channel (%d > %d)\n",KERN_DEBUG, hdr.hdr_attach.chan, crd->card->nr_chans);
h_reply (q, &hdr, EINVAL);
splx (ms);
break;
}
if ((crd->status != C_up) && !(hdr.hdr_attach.listen & 2)) {
printf("%s -- card down 3",KERN_DEBUG);
if(hdr.hdr_attach.listen & 4)
err = (*crd->card->ch_mode) (crd->card, 0, M_ON, 0);
else
err = -ENXIO;
if(err != 0) {
h_reply (q, &hdr, err);
splx (ms);
break;
}
}
if (hdr.hdr_attach.chan > 0) { /* B channel */
if (crd->chan[hdr.hdr_attach.chan] != NULL && crd->chan[hdr.hdr_attach.chan] != chan) {
#if 1
printf ("%s -- Err Chan busy\n",KERN_DEBUG);
h_reply (q, &hdr, EBUSY);
splx (ms);
break;
#else
isdn2_disconnect (chan, 0xFF);
#endif
}
if (hdr.hdr_attach.connref != 0 && chan->connref != 0 && chan->connref != hdr.hdr_attach.connref) {
#if 1
printf ("%s -- Err Chan attached %ld\n",KERN_DEBUG,chan->connref);
h_reply (q, &hdr, EBUSY);
splx (ms);
break;
#else
isdn2_disconnect (chan, 0xFF);
#endif
}
if ((err = (*crd->card->ch_mode) (crd->card, hdr.hdr_attach.chan, M_ON, hdr.hdr_attach.listen & 3)) != 0) {
printf ("%s -- Err SetMode\n",KERN_DEBUG);
h_reply (q, &hdr, EIO);
splx (ms);
break;
}
crd->chan[hdr.hdr_attach.chan] = chan;
chan->status = M_B_conn;
chan->card = crd;
chan->channel = hdr.hdr_attach.chan;
if(hdr.hdr_attach.connref != 0)
chan->connref = hdr.hdr_attach.connref;
} else { /* D channel */
int i;
for (i = crd->card->nr_chans+1; i <= MAXCHAN; i++)
if (crd->chan[i] == NULL || crd->chan[i] == chan)
break;
if (i >= MAXCHAN) {
if (isdn2_debug & 0x10)
printf ("%s -- Err no chan free\n",KERN_DEBUG);
h_reply (q, &hdr, EBUSY);
splx (ms);
break;
}
crd->chan[i] = chan;
chan->status = M_D_conn;
chan->card = crd;
chan->channel = i;
chan->connref = hdr.hdr_attach.connref;
/* putproto (minor, PROTO_CONNECTED); */
if (isdn2_debug & 0x10)
printf ("%s -- Conn D\n",KERN_DEBUG);
}
h_reply(q,&hdr,0);
splx (ms);
}
break;
case HDR_DETACH:
{
NOLENHDR ();
xMINOR (detach);
if (isdn2_debug & 0x10)
printf ("%sDetach minor %d connref %ld%s\n",KERN_DEBUG,
minor, hdr.hdr_detach.connref, hdr.hdr_detach.perm ? " force" : "");
if ((hdr.hdr_detach.connref != 0) && (chan->connref != 0) && (chan->connref != hdr.hdr_detach.connref)) {
printf ("%s -- bad connref\n",KERN_DEBUG);
h_reply (q, &hdr, EBUSY);
break;
}
if (hdr.hdr_detach.perm)
poplist (chan->qptr, PUSH_BEFORE);
isdn2_disconnect (chan, hdr.hdr_detach.error);
h_reply(q,&hdr,0);
}
break;
case HDR_LOAD:
{
LENHDR (load);
CARD (load);
if(crd->card->boot == NULL) {
printf ("%s -- Load: no loader\n",KERN_DEBUG);
h_reply (q, &hdr, EIO);
}
if(hdr.hdr_load.seqnum == 1 && hdr.hdr_load.foffset == 0)
isdn2_new_state(crd->card,0);
if((err = (*crd->card->boot) (crd->card, hdr.hdr_load.seqnum, hdr.hdr_load.foffset, mp)) != 0) {
printf ("%s -- Err Load %d\n",KERN_DEBUG,err);
h_reply (q, &hdr, err);
} else {
mp = NULL;
h_reply (q, &hdr, 0);
}
break;
}
case HDR_TEI:
{
uchar_t ch;
NOLENHDR ();
CARD (tei);
#ifdef DO_MULTI_TEI
ch=hdr.hdr_tei.bchan;
#else
ch=0;
#endif
if (hdr.hdr_tei.TEI != TEI_BROADCAST && crd->TEI[ch] != TEI_REQUESTED &&
crd->TEI[ch] != TEI_BROADCAST && hdr.hdr_tei.TEI != crd->TEI[ch]) {
h_reply (q, &hdr, EINVAL);
break;
}
crd->TEI[ch] = hdr.hdr_tei.TEI;
if (hdr.hdr_tei.TEI == TEI_BROADCAST) {
/*
* Duplicate TEI, or TEI not assignable.
* Deassign. Kick all states.
*/
int ms = splstr ();
if (crd->card->modes & CHM_INTELLIGENT) {
if(crd->state[ch] != NULL)
D_state(crd->state[ch],MDL_REMOVE_REQ,0);
} else {
for (state = crd->state[ch]; state != NULL; state = state->next)
x75_changestate (&state->state, MDL_REMOVE_REQ, 0);
}
splx (ms);
} else {
/*
* TEI (re)assigned. Reestablish.
*/
int ms = splstr ();
if (crd->card->modes & CHM_INTELLIGENT) {
if(crd->state[ch] != NULL)
D_state (crd->state[ch], DL_ESTABLISH_IND, 0);
} else {
for (state = crd->state[ch]; state != NULL; state = state->next) {
if(isdn2_debug&0x40)
printf("%sWakeup %d/%d/%d",KERN_DEBUG,state->card->nr, state->SAPI, *state->card->TEI);
if(state->card != crd)
printf("\n*!*Bad state for card!\n");
x75_changestate (&state->state, DL_ESTABLISH_IND, 0);
}
}
splx (ms);
}
}
break;
case HDR_CARD:
{
NOLENHDR ();
CARD (card);
if (hdr.hdr_card.bchans != crd->card->nr_chans) {
h_reply (q, &hdr, EINVAL);
break;
}
crd->flags = hdr.hdr_card.flags;
if (crd->status != C_up)
h_reply (q, &hdr, D_L1_up (crd));
}
break;
case HDR_NOCARD:
{
NOLENHDR ();
CARD (nocard);
h_reply (q, &hdr, D_L1_down (crd));
}
break;
case HDR_OPENPROT:
{
NOLENHDR ();
CARD (openprot);
if((hdr.hdr_notify.SAPI == SAPI_INVALID) || (hdr.hdr_notify.SAPI == SAPI_FIXED)) {
if(crd->timedown == 1) {
#ifdef OLD_TIMEOUT
untimeout (D_takedown, card);
#else
untimeout (crd->timer_takedown);
#endif
}
crd->timedown = 2;
D_L1_up(crd);
} else {
#ifdef DO_MULTI_TEI
state = D__findstate (crd, hdr.hdr_openprot.SAPI,hdr.hdr_openprot.bchan);
#else
state = D__findstate (crd, hdr.hdr_openprot.SAPI,0);
#endif
if ((state == NULL) != (hdr.hdr_openprot.ind == 0)) {
#ifdef CONFIG_DEBUG_ISDN
printf("%sErr state 0x%p ind 0x%x\n",KERN_DEBUG,state,hdr.hdr_openprot.ind);
#endif
h_reply (q, &hdr, EINVAL);
break;
}
if (state == NULL) {
#ifdef DO_MULTI_TEI
h_reply (q, &hdr, D_register (crd, hdr.hdr_openprot.SAPI, hdr.hdr_openprot.bchan, hdr.hdr_openprot.broadcast));
#else
h_reply (q, &hdr, D_register (crd, hdr.hdr_openprot.SAPI, 0, hdr.hdr_openprot.broadcast));
#endif
} else {
if (crd->card->modes & CHM_INTELLIGENT)
D_state(state,hdr.hdr_openprot.ind,0);
else
x75_changestate (&state->state, hdr.hdr_openprot.ind, 0);
}
D_checkactive (crd);
}
}
break;
case HDR_CLOSEPROT:
{
NOLENHDR ();
CARD (closeprot);
if((hdr.hdr_notify.SAPI == SAPI_INVALID) || (hdr.hdr_notify.SAPI == SAPI_FIXED)) {
if(crd->timedown == 2)
crd->timedown = 0;
D_L1_down(crd);
} else {
#ifdef DO_MULTI_TEI
state = D__findstate (crd, hdr.hdr_closeprot.SAPI,hdr.hdr_closeprot.bchan);
#else
state = D__findstate (crd, hdr.hdr_closeprot.SAPI,0);
#endif
if (state == NULL) {
h_reply (q, &hdr, EINVAL);
break;
}
if (hdr.hdr_closeprot.ind == 0)
h_reply (q, &hdr, D_kill_one (state, hdr.hdr_closeprot.ind));
else if (crd->card->modes & CHM_INTELLIGENT)
D_state(state,hdr.hdr_closeprot.ind,0);
else
x75_changestate (&state->state, hdr.hdr_closeprot.ind, 0);
}
D_checkactive (crd);
}
break;
case HDR_NOTIFY:
{
NOLENHDR ();
CARD (notify);
#ifdef DO_MULTI_TEI
state = D__findstate (crd, hdr.hdr_notify.SAPI,hdr.hdr_notify.bchan);
#else
state = D__findstate (crd, hdr.hdr_notify.SAPI,0);
#endif
if (state == NULL) {
h_reply (q, &hdr, EINVAL);
break;
}
if (crd->card->modes & CHM_INTELLIGENT)
D_state(state,hdr.hdr_notify.ind,0);
else
x75_changestate (&state->state, hdr.hdr_notify.ind, 0);
D_checkactive (crd);
}
break;
case HDR_INVAL:
{
XLENHDR (sizeof (struct _isdn23_hdr));
if (mp != NULL) {
freemsg (mp);
mp = NULL;
}
h_reply (q, &hdr, EINVAL);
}
break;
} /* switch */
free_it:
if (mp != NULL) {
freemsg (mp);
mp = NULL;
}
}
break;
case M_B_conn:
{
struct _isdn1_card *crd1;
if (chan->card != NULL && (crd1 = chan->card->card) != NULL) {
if ((*crd1->cansend) (crd1, chan->channel)) {
if ((*crd1->send) (crd1, chan->channel, mp) != 0) {
putbqf (q, mp);
if(0)printf ("%s.\n",KERN_DEBUG);
return;
} else
if(0)printf("%sC\n",KERN_DEBUG);
} else {
if(0)printf ("%s,\n",KERN_DEBUG);
putbqff(q, mp);
return;
}
} else {
freemsg (mp);
if(0)printf ("Hang 5\n");
putctlx (RD (q), M_HANGUP);
}
}
mp = NULL;
break;
case M_D_conn:
{
isdn23_hdr hdr3;
mblk_t *mz = allocb (sizeof (struct _isdn23_hdr), BPRI_MED);
if(isdn2_debug&0x200) printf(".DConn");
if (mz == NULL) {
putbqf (q, mp);
return;
}
hdr3 = ((isdn23_hdr) mz->b_wptr)++;
hdr3->key = HDR_XDATA;
hdr3->seqnum = hdrseq; hdrseq += 2;
hdr3->hdr_xdata.minor = chan->dev;
hdr3->hdr_xdata.len = dsize (mp);
linkb (mz, mp);
if (isdn_chan.qptr != NULL) {
if(isdn2_debug & 0x2000) logh_printmsg (NULL, "Up", mz);
if(canput(isdn_chan.qptr->q_next))
putnext (isdn_chan.qptr, mz);
else
freemsg(mz);
} else {
freemsg (mz);
printf ("Hang 6\n");
putctlx (RD (q), M_HANGUP);
}
}
mp = NULL;
break;
case M_free:
{
if(isdn2_debug&0x200) printf(".Free");
freemsg (mp);
mp = NULL;
}
break;
}
if (mp != NULL && (mp = pullupm (mp, 0)) != NULL) {
if(isdn2_debug&0x200) printf(".PutBack2.");
putbqf (q, mp);
return;
}
} else if(isdn2_debug&0x200) printf(".MsgEmpty.");
}
}
}
return;
}
static void
isdn2_rsrv (queue_t * q)
{
mblk_t *mp;
while ((mp = getq (q)) != NULL) {
if (q->q_next == NULL) {
freemsg (mp);
continue;
}
if (DATA_TYPE(mp) >= QPCTL || canput (q->q_next)) {
putnext (q, mp);
continue;
} else {
putbq (q, mp);
break;
}
}
return;
}
void
chkfree (void *x)
{
}
#ifdef MODULE
static int devmajor1 = 0;
static int devmajor2 = 0;
static int do_init_module(void)
{
int err;
err = register_strdev(0,&isdn_2info,0);
if(err < 0) return err;
devmajor1 = err;
err = register_strdev(0,&isdn_2tinfo,NPORT);
if(err < 0) {
unregister_strdev(devmajor1,&isdn_2info,0);
return err;
}
devmajor2 = err;
return 0;
}
static int do_exit_module(void)
{
int err1 = unregister_strdev(devmajor1,&isdn_2info,0);
int err2 = unregister_strdev(devmajor2,&isdn_2tinfo,NPORT);
return err1 || err2;
}
#endif