u-isdn/isdn_3/tei.c

539 lines
11 KiB
C

#include "primitives.h"
#include "tei.h"
#include "streamlib.h"
#include "isdn_23.h"
#include "lap.h"
#include "dump.h"
#include <sys/errno.h>
#include <sys/time.h>
#include <sys/param.h>
#include <sys/utsname.h>
#include "sapi.h"
#define TEI_IDREQ 1
#define TEI_IDASS 2
#define TEI_IDDENY 3
#define TEI_IDCHECK_REQ 4
#define TEI_IDCHECK_RESP 5
#define TEI_IDREMOVE 6
#define TEI_IDVERIFY 7
#if NITALK <= 2
#error "Need NITALK > 2"
#endif
#define NR talki[0]
#define TEI_id talki[1]
#ifdef NEW_TIMEOUT
#define timer talki[2]
#endif
#define N201 2
#define T201 2
#define N202 4
#define T202 2
#define ST_inited 02
#define ST_T201 04
#define ST_T202 010
#define ST_up 020
#define ST_want_T202 040
static int
tei_send_id (isdn3_card card, uchar_t TEI)
{
mblk_t *mb;
isdn23_hdr hdr;
int err;
extern int hdrseq;
mb = allocb (sizeof (struct _isdn23_hdr), BPRI_MED);
if (mb == NULL)
return -EAGAIN;
hdr = ((isdn23_hdr) mb->b_wptr)++;
#ifdef __CHECKER__
bzero(hdr,sizeof(*hdr));
#endif
hdr->key = HDR_TEI;
hdr->seqnum = hdrseq; hdrseq += 2;
hdr->hdr_tei.card = card->nr;
hdr->hdr_tei.TEI = TEI;
if ((err = isdn3_sendhdr (mb)) != 0)
freemsg (mb);
card->TEI = TEI;
return err;
}
static void tei_T201 (isdn3_talk talk);
static void tei_T202 (isdn3_talk talk);
static void
tei_init (isdn3_talk talk)
{
static ulong_t id = 1234;
long flags = isdn3_flags(talk->card->info,SAPI_TEI,-1);
/*
* if(!(talk->state & ST_inited)) isdn3_chstate(talk,0,0,CH_OPENPROT);
*/
switch(flags & FL_POINTMASK) {
default:
case FL_MULTIPOINT2:
{
struct utsname foo;
char *x;
uname(&foo); id = 0;
x = foo.sysname ; while(*x) id = id << 1 ^ id >> 8 ^ *x++;
x = foo.nodename ; while(*x) id = id << 2 ^ id >> 7 ^ *x++;
x = foo.machine ; while(*x) id = id << 3 ^ id >> 6 ^ *x++;
x = foo.domainname; while(*x) id = id << 4 ^ id >> 5 ^ *x++;
}
break;
case FL_MULTIPOINT1:
id = getpid() + time(NULL) + (ulong_t)sbrk(0);
break;
}
talk->TEI_id = id;
talk->state |= ST_inited;
}
static void
tei_enquiry (isdn3_talk talk)
{
mblk_t *mb;
int err;
long flags = isdn3_flags(talk->card->info,SAPI_TEI,-1);
if(!(talk->state & ST_inited))
tei_init(talk);
if((flags & FL_POINTMASK) == FL_POINTOPOINT) {
tei_send_id (talk->card,0);
return;
}
if((flags & FL_POINTMASK) == FL_MULTIPOINT3) {
tei_send_id (talk->card, TEI_FIXED);
return;
}
if(talk->state & ST_T201) {
talk->state &=~ ST_T201;
#ifdef NEW_TIMEOUT
untimeout(talk->timer);
#else
untimeout(tei_T201, talk);
#endif
}
mb = allocb (5, BPRI_LO);
if (mb == NULL) {
printf ("No Mem TEIassReq\n");
--talk->NR;
} else {
*mb->b_wptr++ = 0x0F;
*((ushort_t *) mb->b_wptr)++ = (talk->TEI_id &= 0x7F7F);
*mb->b_wptr++ = TEI_IDREQ;
*mb->b_wptr++ = 0xFF;
if ((err = isdn3_send (talk, AS_UIBROADCAST, mb)) != 0) {
--talk->NR;
freemsg (mb);
}
}
if (talk->state & ST_up) {
printf("Timer T202 started\n");
talk->state |= ST_T202;
talk->state &=~ ST_want_T202;
#ifdef NEW_TIMEOUT
talk->timer =
#endif
timeout (tei_T202, talk, T202 * HZ);
} else {
if(0)printf("Wait for ST_up before starting T202\n");
talk->state |= ST_want_T202;
}
}
static void
tei_verify (isdn3_talk talk)
{
mblk_t *mb;
int err;
if(talk->state & (ST_T201|ST_T202))
return;
else if(!(talk->state & ST_up)) {
tei_enquiry(talk);
return;
}
mb = allocb (5, BPRI_LO);
if (mb == NULL) {
printf ("No Mem TEIassReq\n");
--talk->NR;
} else {
*mb->b_wptr++ = 0x0F;
*((ushort_t *) mb->b_wptr)++ = talk->TEI_id;
*mb->b_wptr++ = TEI_IDVERIFY;
*mb->b_wptr++ = 0xFF;
if ((err = isdn3_send (talk, AS_UIBROADCAST, mb)) != 0) {
--talk->NR;
freemsg (mb);
}
}
talk->state |= ST_T201;
#ifdef NEW_TIMEOUT
talk->timer =
#endif
timeout (tei_T201, talk, T201 * HZ);
}
static void
tei_T201 (isdn3_talk talk)
{
printf ("Timer TEI T201 %ld\n", talk->NR);
if (talk->state & ST_T201) {
talk->state &= ~ST_T201;
if (!(talk->state & ST_up)) {
talk->state |= ST_want_T202;
return;
}
if (talk->NR >= N201 && tei_send_id (talk->card, TEI_BROADCAST) != -EAGAIN) {
tei_enquiry(talk);
} else {
talk->NR++;
tei_verify (talk);
}
}
}
static void
tei_T202 (isdn3_talk talk)
{
printf ("Timer TEI T202 %ld\n", talk->NR);
if (talk->state & ST_T202) {
talk->state &= ~ST_T202;
if (!(talk->state & ST_up)) {
talk->state |= ST_want_T202;
return;
}
if (talk->NR >= N202) {
if (tei_send_id (talk->card, TEI_BROADCAST) == -EAGAIN) {
talk->state |= ST_T202;
talk->state &=~ ST_want_T202;
#ifdef NEW_TIMEOUT
talk->timer =
#endif
timeout (&tei_T202, talk, T202 * HZ);
}
} else {
talk->NR++;
tei_enquiry (talk);
}
}
}
static int
tei_chstate (isdn3_talk talk, uchar_t ind, short add)
{
if(0)printf ("TEI state for card %d says %s:%o\n", talk->card->nr, conv_ind(ind), add);
switch (ind) {
case PH_ACTIVATE_IND:
case PH_ACTIVATE_CONF:
talk->state |= ST_up;
if(talk->state & ST_want_T202) {
talk->state |= ST_T202;
talk->state &=~ ST_want_T202;
#ifdef NEW_TIMEOUT
talk->timer =
#endif
timeout (tei_T202, talk, T202 * HZ);
}
break;
case PH_DEACTIVATE_IND:
case PH_DEACTIVATE_CONF:
talk->state &= ~ST_up;
if (talk->state & ST_T202) {
talk->state &=~ ST_T202;
#ifdef NEW_TIMEOUT
untimeout(talk->timer);
#else
untimeout (tei_T202, talk);
#endif
} else if (talk->state & ST_T201) {
talk->state &=~ ST_T201;
#ifdef NEW_TIMEOUT
untimeout(talk->timer);
#else
untimeout (tei_T201, talk);
#endif
}
/* Try again? */
if(talk->card->TEI == TEI_BROADCAST)
tei_enquiry(talk);
break;
case PH_DISCONNECT_IND:
talk->state &= ~ST_inited; /* Leave this bit on, if and when */
if (talk->state & ST_T202) {
#ifdef NEW_TIMEOUT
untimeout(talk->timer);
#else
untimeout (tei_T202, talk);
#endif
} else if (talk->state & ST_T201) {
#ifdef NEW_TIMEOUT
untimeout(talk->timer);
#else
untimeout (tei_T201, talk);
#endif
}
break;
case MDL_ERROR_IND:
if(talk->state & ST_up)
tei_verify(talk);
else
talk->state |= ST_want_T202;
break;
}
return 0;
}
static int
tei_recv (isdn3_talk talk, char isUI, mblk_t * data)
{
ushort_t id;
uchar_t key;
mblk_t *mb;
uchar_t TEI;
long flags = isdn3_flags(talk->card->info,SAPI_TEI,-1);
if (talk->state == 0) {
tei_init (talk);
}
if (!(isUI & 2)) { /* got to be a broadcast */
printf("TEI RejNoBroadcast\n");
return -EINVAL;
}
mb = pullupm (data, 4);
if (mb == NULL)
return -ENOMEM;
/* Do not return nonzero after this point */
if (*mb->b_rptr++ != 0x0F) {
freemsg (mb);
return 0;
}
id = *((ushort_t *) mb->b_rptr)++;
key = *mb->b_rptr++;
mb = pullupm (mb, 0);
TEI = *mb->b_rptr;
if (!(TEI & 1))
return 0;
TEI >>= 1;
printf("R Key %x for %d\n",TEI, key);
switch (key) {
case TEI_IDDENY:
if (id != (talk->TEI_id & 0xFFFF))
break;
switch(flags & FL_POINTMASK) {
case FL_POINTOPOINT:
TEI = 0;
goto cfix;
case FL_MULTIPOINT3:
TEI = TEI_FIXED;
cfix:
printf("Fixed TEI %d\n",TEI);
if (talk->state & ST_T202) {
talk->state &=~ ST_T202;
#ifdef NEW_TIMEOUT
untimeout(talk->timer);
#else
untimeout (tei_T202, talk);
#endif
} else if (talk->state & ST_T201) {
talk->state &=~ ST_T201;
#ifdef NEW_TIMEOUT
untimeout(talk->timer);
#else
untimeout (tei_T201, talk);
#endif
}
tei_send_id (talk->card, TEI);
break;
default:
printf("NonFixed TEI\n");
tei_send_id (talk->card, TEI_BROADCAST);
break;
}
tei_init (talk);
break;
case TEI_IDASS:
if (id != (talk->TEI_id & 0xFFFF))
break;
if (talk->state & ST_T202) {
talk->state &=~ ST_T202;
#ifdef NEW_TIMEOUT
untimeout(talk->timer);
#else
untimeout (tei_T202, talk);
#endif
if (talk->state & ST_up) {
tei_send_id (talk->card, TEI);
tei_init (talk);
} else
printf ("TEI assign of %d without req\n", TEI);
} else if (talk->state & ST_T201) {
talk->state &=~ ST_T201;
#ifdef NEW_TIMEOUT
untimeout(talk->timer);
#else
untimeout (tei_T201, talk);
#endif
}
break;
case TEI_IDCHECK_REQ:
if (TEI != TEI_BROADCAST && TEI != talk->card->TEI) {
if (talk->NR > 0)
talk->NR--;
break;
}
if (talk->card->TEI == TEI_BROADCAST)
break;
{
mblk_t *mp;
int err;
if ((mp = allocb (5, BPRI_LO)) == NULL) {
printf ("No Mem TEIchkReq\n");
} else {
*mp->b_wptr++ = 0x0F;
*((ushort_t *) mp->b_wptr)++ = talk->TEI_id;
*mp->b_wptr++ = TEI_IDCHECK_RESP;
*mp->b_wptr++ = (talk->card->TEI << 1) | 1;;
if ((err = isdn3_send (talk, AS_UIBROADCAST, mp)) != 0) {
freemsg (mp);
}
}
if(talk->state & ST_T202) {
talk->state &=~ ST_T202;
#ifdef NEW_TIMEOUT
untimeout(talk->timer);
#else
untimeout(tei_T202, talk);
#endif
} else if(talk->state & ST_T201) {
talk->state &=~ ST_T201;
#ifdef NEW_TIMEOUT
untimeout(talk->timer);
#else
untimeout(tei_T201, talk);
#endif
}
}
break;
case TEI_IDREMOVE:
if (TEI != talk->card->TEI)
break;
if(talk->state & ST_T202) {
talk->state &=~ ST_T202;
#ifdef NEW_TIMEOUT
untimeout(talk->timer);
#else
untimeout(tei_T202, talk);
#endif
} else if(talk->state & ST_T201) {
talk->state &=~ ST_T201;
#ifdef NEW_TIMEOUT
untimeout(talk->timer);
#else
untimeout(tei_T201, talk);
#endif
}
tei_send_id (talk->card, TEI_BROADCAST);
break;
}
if (mb != NULL)
freemsg (mb);
return 0;
}
static int
tei_sendcmd (isdn3_conn conn, ushort_t id, mblk_t * data)
{
printf("TEI SendCmd Foo ");
return -EINVAL;
}
static int
tei_send (isdn3_conn conn, mblk_t * data)
{
return -EINVAL;
}
static void
tei_kill (isdn3_talk talk, char force)
{
if (talk->state & ST_T202) {
talk->state &=~ ST_T202;
#ifdef NEW_TIMEOUT
untimeout(talk->timer);
#else
untimeout (tei_T202, talk);
#endif
} else if (talk->state & ST_T201) {
talk->state &=~ ST_T201;
#ifdef NEW_TIMEOUT
untimeout(talk->timer);
#else
untimeout (tei_T201, talk);
#endif
}
if (talk->state & ST_inited) {
isdn3_chstate (talk, 0, 0, CH_CLOSEPROT);
talk->state &=~ ST_inited;
}
}
static void
tei_newcard (isdn3_card card)
{
long flags = isdn3_flags(card->info,SAPI_TEI,-1);
(void) isdn3_findtalk (card, &TEI_hndl, NULL, 1);
if(flags & FL_TEI_IMMED)
tei_getid (card);
}
static ulong_t
tei_modeflags (long protocol)
{
return 0;
}
int
tei_getid (isdn3_card card)
{
isdn3_hndl hndl;
isdn3_talk talk;
if ((hndl = isdn3_findhndl (SAPI_TEI)) == NULL)
return -ENXIO;
if ((talk = isdn3_findtalk (card, hndl, NULL, 0)) == NULL)
return -ENXIO;
if (!talk->state & ST_inited)
tei_init (talk);
if (talk->state & ST_T202)
return 0;
talk->NR = 0;
if(0)printf ("TEI GetId\n");
tei_enquiry (talk);
return 0;
}
struct _isdn3_hndl TEI_hndl =
{
NULL, SAPI_TEI,1,
NULL, &tei_newcard, &tei_modeflags, &tei_chstate, NULL, &tei_recv,
&tei_send, &tei_sendcmd, &tei_kill, NULL, NULL, NULL,
};