/* $Id: l3_1tr6.c,v 2.15.2.3 2004/01/13 14:31:25 keil Exp $
*
* German 1TR6 D-channel protocol
*
* Author Karsten Keil
* 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
*
*/
#include "hisax.h"
#include "l3_1tr6.h"
#include "isdnl3.h"
#include <linux/ctype.h>
extern char *HiSax_getrev(const char *revision);
static const char *l3_1tr6_revision = "$Revision: 2.15.2.3 $";
#define MsgHead(ptr, cref, mty, dis) \
*ptr++ = dis; \
*ptr++ = 0x1; \
*ptr++ = cref ^ 0x80; \
*ptr++ = mty
static void
l3_1TR6_message(struct l3_process *pc, u_char mt, u_char pd)
{
struct sk_buff *skb;
u_char *p;
if (!(skb = l3_alloc_skb(4)))
return;
p = skb_put(skb, 4);
MsgHead(p, pc->callref, mt, pd);
l3_msg(pc->st, DL_DATA | REQUEST, skb);
}
static void
l3_1tr6_release_req(struct l3_process *pc, u_char pr, void *arg)
{
StopAllL3Timer(pc);
newl3state(pc, 19);
l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1);
L3AddTimer(&pc->timer, T308, CC_T308_1);
}
static void
l3_1tr6_invalid(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
dev_kfree_skb(skb);
l3_1tr6_release_req(pc, 0, NULL);
}
static void
l3_1tr6_error(struct l3_process *pc, u_char *msg, struct sk_buff *skb)
{
dev_kfree_skb(skb);
if (pc->st->l3.debug & L3_DEB_WARN)
l3_debug(pc->st, "%s", msg);
l3_1tr6_release_req(pc, 0, NULL);
}
static void
l3_1tr6_setup_req(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb;
u_char tmp[128];
u_char *p = tmp;
u_char *teln;
u_char *eaz;
u_char channel = 0;
int l;
MsgHead(p, pc->callref, MT_N1_SETUP, PROTO_DIS_N1);
teln = pc->para.setup.phone;
pc->para.spv = 0;
if (!isdigit(*teln)) {
switch (0x5f & *teln) {
case 'S':
pc->para.spv = 1;
break;
case 'C':
channel = 0x08;
case 'P':
channel |= 0x80;
teln++;
if (*teln == '1')
channel |= 0x01;
else
channel |= 0x02;
break;
default:
if (pc->st->l3.debug & L3_DEB_WARN)
l3_debug(pc->st, "Wrong MSN Code");
break;
}
teln++;
}
if (channel) {
*p++ = 0x18; /* channel indicator */
*p++ = 1;
*p++ = channel;
}
if (pc->para.spv) { /* SPV ? */
/* NSF SPV */
*p++ = WE0_netSpecFac;
*p++ = 4; /* Laenge */
*p++ = 0;
*p++ = FAC_SPV; /* SPV */
*p++ = pc->para.setup.si1; /* 0 for all Services */
*p++ = pc->para.setup.si2; /* 0 for all Services */
*p++ = WE0_netSpecFac;
*p++ = 4; /* Laenge */
*p++ = 0;
*p++ = FAC_Activate; /* aktiviere SPV (default) */
*p++ = pc->para.setup.si1; /* 0 for all Services */
*p++ = pc->para.setup.si2; /* 0 for all Services */
}
eaz = pc->para.setup.eazmsn;
if (*eaz) {
*p++ = WE0_origAddr;
*p++ = strlen(eaz) + 1;
/* Classify as AnyPref. */
*p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
while (*eaz)
*p++ = *eaz++ & 0x7f;
}
*p++ = WE0_destAddr;
*p++ = strlen(teln) + 1;
/* Classify as AnyPref. */
*p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */