Logo Search packages:      
Sourcecode: linux version File versions  Download package

tei.c

/* $Id: tei.c,v 2.20.2.3 2004/01/13 14:31:26 keil Exp $
 *
 * Author       Karsten Keil
 *              based on the teles driver from Jan den Ouden
 * Copyright    by Karsten Keil      <keil@isdn4linux.de>
 * 
 * This software may be used and distributed according to the terms
 * of the GNU General Public License, incorporated herein by reference.
 *
 * For changes and modifications please read
 * Documentation/isdn/HiSax.cert
 *
 * Thanks to    Jan den Ouden
 *              Fritz Elfert
 *
 */

#include "hisax.h"
#include "isdnl2.h"
#include <linux/init.h>
#include <linux/random.h>

const char *tei_revision = "$Revision: 2.20.2.3 $";

#define ID_REQUEST      1
#define ID_ASSIGNED     2
#define ID_DENIED 3
#define ID_CHK_REQ      4
#define ID_CHK_RES      5
#define ID_REMOVE 6
#define ID_VERIFY 7

#define TEI_ENTITY_ID   0xf

static struct Fsm teifsm;

void tei_handler(struct PStack *st, u_char pr, struct sk_buff *skb);

enum {
      ST_TEI_NOP,
      ST_TEI_IDREQ,
      ST_TEI_IDVERIFY,
};

#define TEI_STATE_COUNT (ST_TEI_IDVERIFY+1)

static char *strTeiState[] =
{
      "ST_TEI_NOP",
      "ST_TEI_IDREQ",
      "ST_TEI_IDVERIFY",
};

enum {
      EV_IDREQ,
      EV_ASSIGN,
      EV_DENIED,
      EV_CHKREQ,
      EV_REMOVE,
      EV_VERIFY,
      EV_T202,
};

#define TEI_EVENT_COUNT (EV_T202+1)

static char *strTeiEvent[] =
{
      "EV_IDREQ",
      "EV_ASSIGN",
      "EV_DENIED",
      "EV_CHKREQ",
      "EV_REMOVE",
      "EV_VERIFY",
      "EV_T202",
};

static unsigned int
random_ri(void)
{
      unsigned int x;

      get_random_bytes(&x, sizeof(x));
      return (x & 0xffff);
}

static struct PStack *
findtei(struct PStack *st, int tei)
{
      struct PStack *ptr = *(st->l1.stlistp);

      if (tei == 127)
            return (NULL);

      while (ptr)
            if (ptr->l2.tei == tei)
                  return (ptr);
            else
                  ptr = ptr->next;
      return (NULL);
}

static void
put_tei_msg(struct PStack *st, u_char m_id, unsigned int ri, u_char tei)
{
      struct sk_buff *skb;
      u_char *bp;

      if (!(skb = alloc_skb(8, GFP_ATOMIC))) {
            printk(KERN_WARNING "HiSax: No skb for TEI manager\n");
            return;
      }
      bp = skb_put(skb, 3);
      bp[0] = (TEI_SAPI << 2);
      bp[1] = (GROUP_TEI << 1) | 0x1;
      bp[2] = UI;
      bp = skb_put(skb, 5);
      bp[0] = TEI_ENTITY_ID;
      bp[1] = ri >> 8;
      bp[2] = ri & 0xff;
      bp[3] = m_id;
      bp[4] = (tei << 1) | 1;
      st->l2.l2l1(st, PH_DATA | REQUEST, skb);
}

static void
tei_id_request(struct FsmInst *fi, int event, void *arg)
{
      struct PStack *st = fi->userdata;

      if (st->l2.tei != -1) {
            st->ma.tei_m.printdebug(&st->ma.tei_m,
                  "assign request for allready asigned tei %d",
                  st->l2.tei);
            return;
      }
      st->ma.ri = random_ri();
      if (st->ma.debug)
            st->ma.tei_m.printdebug(&st->ma.tei_m,
                  "assign request ri %d", st->ma.ri);
      put_tei_msg(st, ID_REQUEST, st->ma.ri, 127);
      FsmChangeState(&st->ma.tei_m, ST_TEI_IDREQ);
      FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 1);
      st->ma.N202 = 3;
}

static void
tei_id_assign(struct FsmInst *fi, int event, void *arg)
{
      struct PStack *ost, *st = fi->userdata;
      struct sk_buff *skb = arg;
      struct IsdnCardState *cs;
      int ri, tei;

      ri = ((unsigned int) skb->data[1] << 8) + skb->data[2];
      tei = skb->data[4] >> 1;
      if (st->ma.debug)
            st->ma.tei_m.printdebug(&st->ma.tei_m,
                  "identity assign ri %d tei %d", ri, tei);
      if ((ost = findtei(st, tei))) {     /* same tei is in use */
            if (ri != ost->ma.ri) {
                  st->ma.tei_m.printdebug(&st->ma.tei_m,
                        "possible duplicate assignment tei %d", tei);
                  ost->l2.l2tei(ost, MDL_ERROR | RESPONSE, NULL);
            }
      } else if (ri == st->ma.ri) {
            FsmDelTimer(&st->ma.t202, 1);
            FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
            st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) tei);
            cs = (struct IsdnCardState *) st->l1.hardware;
            cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL);
      }
}

static void
tei_id_test_dup(struct FsmInst *fi, int event, void *arg)
{
      struct PStack *ost, *st = fi->userdata;
      struct sk_buff *skb = arg;
      int tei, ri;

      ri = ((unsigned int) skb->data[1] << 8) + skb->data[2];
      tei = skb->data[4] >> 1;
      if (st->ma.debug)
            st->ma.tei_m.printdebug(&st->ma.tei_m,
                  "foreign identity assign ri %d tei %d", ri, tei);
      if ((ost = findtei(st, tei))) {     /* same tei is in use */
            if (ri != ost->ma.ri) { /* and it wasn't our request */
                  st->ma.tei_m.printdebug(&st->ma.tei_m,
                        "possible duplicate assignment tei %d", tei);
                  FsmEvent(&ost->ma.tei_m, EV_VERIFY, NULL);
            }
      } 
}

static void
tei_id_denied(struct FsmInst *fi, int event, void *arg)
{
      struct PStack *st = fi->userdata;
      struct sk_buff *skb = arg;
      int ri, tei;

      ri = ((unsigned int) skb->data[1] << 8) + skb->data[2];
      tei = skb->data[4] >> 1;
      if (st->ma.debug)
            st->ma.tei_m.printdebug(&st->ma.tei_m,
                  "identity denied ri %d tei %d", ri, tei);
}

static void
tei_id_chk_req(struct FsmInst *fi, int event, void *arg)
{
      struct PStack *st = fi->userdata;
      struct sk_buff *skb = arg;
      int tei;

      tei = skb->data[4] >> 1;
      if (st->ma.debug)
            st->ma.tei_m.printdebug(&st->ma.tei_m,
                  "identity check req tei %d", tei);
      if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) {
            FsmDelTimer(&st->ma.t202, 4);
            FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
            put_tei_msg(st, ID_CHK_RES, random_ri(), st->l2.tei);
      }
}

static void
tei_id_remove(struct FsmInst *fi, int event, void *arg)
{
      struct PStack *st = fi->userdata;
      struct sk_buff *skb = arg;
      struct IsdnCardState *cs;
      int tei;

      tei = skb->data[4] >> 1;
      if (st->ma.debug)
            st->ma.tei_m.printdebug(&st->ma.tei_m,
                  "identity remove tei %d", tei);
      if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) {
            FsmDelTimer(&st->ma.t202, 5);
            FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
            st->l3.l3l2(st, MDL_REMOVE | REQUEST, NULL);
            cs = (struct IsdnCardState *) st->l1.hardware;
            cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
      }
}

static void
tei_id_verify(struct FsmInst *fi, int event, void *arg)
{
      struct PStack *st = fi->userdata;

      if (st->ma.debug)
            st->ma.tei_m.printdebug(&st->ma.tei_m,
                  "id verify request for tei %d", st->l2.tei);
      put_tei_msg(st, ID_VERIFY, 0, st->l2.tei);
      FsmChangeState(&st->ma.tei_m, ST_TEI_IDVERIFY);
      FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 2);
      st->ma.N202 = 2;
}

static void
tei_id_req_tout(struct FsmInst *fi, int event, void *arg)
{
      struct PStack *st = fi->userdata;
      struct IsdnCardState *cs;

      if (--st->ma.N202) {
            st->ma.ri = random_ri();
            if (st->ma.debug)
                  st->ma.tei_m.printdebug(&st->ma.tei_m,
                        "assign req(%d) ri %d", 4 - st->ma.N202,
                        st->ma.ri);
            put_tei_msg(st, ID_REQUEST, st->ma.ri, 127);
            FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 3);
      } else {
            st->ma.tei_m.printdebug(&st->ma.tei_m, "assign req failed");
            st->l3.l3l2(st, MDL_ERROR | RESPONSE, NULL);
            cs = (struct IsdnCardState *) st->l1.hardware;
            cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
            FsmChangeState(fi, ST_TEI_NOP);
      }
}

static void
tei_id_ver_tout(struct FsmInst *fi, int event, void *arg)
{
      struct PStack *st = fi->userdata;
      struct IsdnCardState *cs;

      if (--st->ma.N202) {
            if (st->ma.debug)
                  st->ma.tei_m.printdebug(&st->ma.tei_m,
                        "id verify req(%d) for tei %d",
                        3 - st->ma.N202, st->l2.tei);
            put_tei_msg(st, ID_VERIFY, 0, st->l2.tei);
            FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 4);
      } else {
            st->ma.tei_m.printdebug(&st->ma.tei_m,
                  "verify req for tei %d failed", st->l2.tei);
            st->l3.l3l2(st, MDL_REMOVE | REQUEST, NULL);
            cs = (struct IsdnCardState *) st->l1.hardware;
            cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
            FsmChangeState(fi, ST_TEI_NOP);
      }
}

static void
tei_l1l2(struct PStack *st, int pr, void *arg)
{
      struct sk_buff *skb = arg;
      int mt;

      if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) {
            dev_kfree_skb(skb);
            return;
      }

      if (pr == (PH_DATA | INDICATION)) {
            if (skb->len < 3) {
                  st->ma.tei_m.printdebug(&st->ma.tei_m,
                        "short mgr frame %ld/3", skb->len);
            } else if ((skb->data[0] != ((TEI_SAPI << 2) | 2)) ||
                     (skb->data[1] != ((GROUP_TEI << 1) | 1))) {
                  st->ma.tei_m.printdebug(&st->ma.tei_m,
                        "wrong mgr sapi/tei %x/%x",
                        skb->data[0], skb->data[1]);
            } else if ((skb->data[2] & 0xef) != UI) {
                  st->ma.tei_m.printdebug(&st->ma.tei_m,
                        "mgr frame is not ui %x", skb->data[2]);
            } else {
                  skb_pull(skb, 3);
                  if (skb->len < 5) {
                        st->ma.tei_m.printdebug(&st->ma.tei_m,
                              "short mgr frame %ld/5", skb->len);
                  } else if (skb->data[0] != TEI_ENTITY_ID) {
                        /* wrong management entity identifier, ignore */
                        st->ma.tei_m.printdebug(&st->ma.tei_m,
                              "tei handler wrong entity id %x",
                              skb->data[0]);
                  } else {
                        mt = skb->data[3];
                        if (mt == ID_ASSIGNED)
                              FsmEvent(&st->ma.tei_m, EV_ASSIGN, skb);
                        else if (mt == ID_DENIED)
                              FsmEvent(&st->ma.tei_m, EV_DENIED, skb);
                        else if (mt == ID_CHK_REQ)
                              FsmEvent(&st->ma.tei_m, EV_CHKREQ, skb);
                        else if (mt == ID_REMOVE)
                              FsmEvent(&st->ma.tei_m, EV_REMOVE, skb);
                        else {
                              st->ma.tei_m.printdebug(&st->ma.tei_m,
                                    "tei handler wrong mt %x\n", mt);
                        }
                  }
            }
      } else {
            st->ma.tei_m.printdebug(&st->ma.tei_m,
                  "tei handler wrong pr %x\n", pr);
      }
      dev_kfree_skb(skb);
}

static void
tei_l2tei(struct PStack *st, int pr, void *arg)
{
      struct IsdnCardState *cs;

      if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) {
            if (pr == (MDL_ASSIGN | INDICATION)) {
                  if (st->ma.debug)
                        st->ma.tei_m.printdebug(&st->ma.tei_m,
                              "fixed assign tei %d", st->l2.tei);
                  st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) st->l2.tei);
                  cs = (struct IsdnCardState *) st->l1.hardware;
                  cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL);
            }
            return;
      }
      switch (pr) {
            case (MDL_ASSIGN | INDICATION):
                  FsmEvent(&st->ma.tei_m, EV_IDREQ, arg);
                  break;
            case (MDL_ERROR | REQUEST):
                  FsmEvent(&st->ma.tei_m, EV_VERIFY, arg);
                  break;
            default:
                  break;
      }
}

static void
tei_debug(struct FsmInst *fi, char *fmt, ...)
{
      va_list args;
      struct PStack *st = fi->userdata;

      va_start(args, fmt);
      VHiSax_putstatus(st->l1.hardware, "tei ", fmt, args);
      va_end(args);
}

void
setstack_tei(struct PStack *st)
{
      st->l2.l2tei = tei_l2tei;
      st->ma.T202 = 2000;     /* T202  2000 milliseconds */
      st->l1.l1tei = tei_l1l2;
      st->ma.debug = 1;
      st->ma.tei_m.fsm = &teifsm;
      st->ma.tei_m.state = ST_TEI_NOP;
      st->ma.tei_m.debug = 1;
      st->ma.tei_m.userdata = st;
      st->ma.tei_m.userint = 0;
      st->ma.tei_m.printdebug = tei_debug;
      FsmInitTimer(&st->ma.tei_m, &st->ma.t202);
}

void
init_tei(struct IsdnCardState *cs, int protocol)
{
}

void
release_tei(struct IsdnCardState *cs)
{
      struct PStack *st = cs->stlist;

      while (st) {
            FsmDelTimer(&st->ma.t202, 1);
            st = st->next;
      }
}

static struct FsmNode TeiFnList[] __initdata =
{
      {ST_TEI_NOP, EV_IDREQ, tei_id_request},
      {ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup},
      {ST_TEI_NOP, EV_VERIFY, tei_id_verify},
      {ST_TEI_NOP, EV_REMOVE, tei_id_remove},
      {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req},
      {ST_TEI_IDREQ, EV_T202, tei_id_req_tout},
      {ST_TEI_IDREQ, EV_ASSIGN, tei_id_assign},
      {ST_TEI_IDREQ, EV_DENIED, tei_id_denied},
      {ST_TEI_IDVERIFY, EV_T202, tei_id_ver_tout},
      {ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove},
      {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req},
};

#define TEI_FN_COUNT (sizeof(TeiFnList)/sizeof(struct FsmNode))

int __init
TeiNew(void)
{
      teifsm.state_count = TEI_STATE_COUNT;
      teifsm.event_count = TEI_EVENT_COUNT;
      teifsm.strEvent = strTeiEvent;
      teifsm.strState = strTeiState;
      return FsmNew(&teifsm, TeiFnList, TEI_FN_COUNT);
}

void
TeiFree(void)
{
      FsmFree(&teifsm);
}

Generated by  Doxygen 1.6.0   Back to index