forked from Minki/linux
cd354f1ae7
After Al Viro (finally) succeeded in removing the sched.h #include in module.h recently, it makes sense again to remove other superfluous sched.h includes. There are quite a lot of files which include it but don't actually need anything defined in there. Presumably these includes were once needed for macros that used to live in sched.h, but moved to other header files in the course of cleaning it up. To ease the pain, this time I did not fiddle with any header files and only removed #includes from .c-files, which tend to cause less trouble. Compile tested against 2.6.20-rc2 and 2.6.20-rc2-mm2 (with offsets) on alpha, arm, i386, ia64, mips, powerpc, and x86_64 with allnoconfig, defconfig, allmodconfig, and allyesconfig as well as a few randconfigs on x86_64 and all configs in arch/arm/configs on arm. I also checked that no new warnings were introduced by the patch (actually, some warnings are removed that were emitted by unnecessarily included header files). Signed-off-by: Tim Schmielau <tim@physik3.uni-rostock.de> Acked-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
653 lines
15 KiB
C
653 lines
15 KiB
C
/*
|
|
* CAPI encoder/decoder for
|
|
* Portugal Telecom CAPI 2.0
|
|
*
|
|
* Copyright (C) 1996 Universidade de Lisboa
|
|
*
|
|
* Written by Pedro Roque Marques (roque@di.fc.ul.pt)
|
|
*
|
|
* This software may be used and distributed according to the terms of
|
|
* the GNU General Public License, incorporated herein by reference.
|
|
*
|
|
* Not compatible with the AVM Gmbh. CAPI 2.0
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Documentation:
|
|
* - "Common ISDN API - Perfil Português - Versão 2.1",
|
|
* Telecom Portugal, Fev 1992.
|
|
* - "Common ISDN API - Especificação de protocolos para
|
|
* acesso aos canais B", Inesc, Jan 1994.
|
|
*/
|
|
|
|
/*
|
|
* TODO: better decoding of Information Elements
|
|
* for debug purposes mainly
|
|
* encode our number in CallerPN and ConnectedPN
|
|
*/
|
|
|
|
#include <linux/string.h>
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/mm.h>
|
|
|
|
#include <linux/skbuff.h>
|
|
|
|
#include <asm/io.h>
|
|
#include <asm/string.h>
|
|
|
|
#include <linux/isdnif.h>
|
|
|
|
#include "pcbit.h"
|
|
#include "edss1.h"
|
|
#include "capi.h"
|
|
|
|
|
|
/*
|
|
* Encoding of CAPI messages
|
|
*
|
|
*/
|
|
|
|
int capi_conn_req(const char * calledPN, struct sk_buff **skb, int proto)
|
|
{
|
|
ushort len;
|
|
|
|
/*
|
|
* length
|
|
* AppInfoMask - 2
|
|
* BC0 - 3
|
|
* BC1 - 1
|
|
* Chan - 2
|
|
* Keypad - 1
|
|
* CPN - 1
|
|
* CPSA - 1
|
|
* CalledPN - 2 + strlen
|
|
* CalledPSA - 1
|
|
* rest... - 4
|
|
* ----------------
|
|
* Total 18 + strlen
|
|
*/
|
|
|
|
len = 18 + strlen(calledPN);
|
|
|
|
if (proto == ISDN_PROTO_L2_TRANS)
|
|
len++;
|
|
|
|
if ((*skb = dev_alloc_skb(len)) == NULL) {
|
|
|
|
printk(KERN_WARNING "capi_conn_req: alloc_skb failed\n");
|
|
return -1;
|
|
}
|
|
|
|
/* InfoElmMask */
|
|
*((ushort*) skb_put(*skb, 2)) = AppInfoMask;
|
|
|
|
if (proto == ISDN_PROTO_L2_TRANS)
|
|
{
|
|
/* Bearer Capability - Mandatory*/
|
|
*(skb_put(*skb, 1)) = 3; /* BC0.Length */
|
|
*(skb_put(*skb, 1)) = 0x80; /* Speech */
|
|
*(skb_put(*skb, 1)) = 0x10; /* Circuit Mode */
|
|
*(skb_put(*skb, 1)) = 0x23; /* A-law */
|
|
}
|
|
else
|
|
{
|
|
/* Bearer Capability - Mandatory*/
|
|
*(skb_put(*skb, 1)) = 2; /* BC0.Length */
|
|
*(skb_put(*skb, 1)) = 0x88; /* Digital Information */
|
|
*(skb_put(*skb, 1)) = 0x90; /* BC0.Octect4 */
|
|
}
|
|
|
|
/* Bearer Capability - Optional*/
|
|
*(skb_put(*skb, 1)) = 0; /* BC1.Length = 0 */
|
|
|
|
*(skb_put(*skb, 1)) = 1; /* ChannelID.Length = 1 */
|
|
*(skb_put(*skb, 1)) = 0x83; /* Basic Interface - Any Channel */
|
|
|
|
*(skb_put(*skb, 1)) = 0; /* Keypad.Length = 0 */
|
|
|
|
|
|
*(skb_put(*skb, 1)) = 0; /* CallingPN.Length = 0 */
|
|
*(skb_put(*skb, 1)) = 0; /* CallingPSA.Length = 0 */
|
|
|
|
/* Called Party Number */
|
|
*(skb_put(*skb, 1)) = strlen(calledPN) + 1;
|
|
*(skb_put(*skb, 1)) = 0x81;
|
|
memcpy(skb_put(*skb, strlen(calledPN)), calledPN, strlen(calledPN));
|
|
|
|
/* '#' */
|
|
|
|
*(skb_put(*skb, 1)) = 0; /* CalledPSA.Length = 0 */
|
|
|
|
/* LLC.Length = 0; */
|
|
/* HLC0.Length = 0; */
|
|
/* HLC1.Length = 0; */
|
|
/* UTUS.Length = 0; */
|
|
memset(skb_put(*skb, 4), 0, 4);
|
|
|
|
return len;
|
|
}
|
|
|
|
int capi_conn_resp(struct pcbit_chan* chan, struct sk_buff **skb)
|
|
{
|
|
|
|
if ((*skb = dev_alloc_skb(5)) == NULL) {
|
|
|
|
printk(KERN_WARNING "capi_conn_resp: alloc_skb failed\n");
|
|
return -1;
|
|
}
|
|
|
|
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
|
|
*(skb_put(*skb, 1)) = 0x01; /* ACCEPT_CALL */
|
|
*(skb_put(*skb, 1)) = 0;
|
|
*(skb_put(*skb, 1)) = 0;
|
|
|
|
return 5;
|
|
}
|
|
|
|
int capi_conn_active_req(struct pcbit_chan* chan, struct sk_buff **skb)
|
|
{
|
|
/*
|
|
* 8 bytes
|
|
*/
|
|
|
|
if ((*skb = dev_alloc_skb(8)) == NULL) {
|
|
|
|
printk(KERN_WARNING "capi_conn_active_req: alloc_skb failed\n");
|
|
return -1;
|
|
}
|
|
|
|
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
|
|
|
|
#ifdef DEBUG
|
|
printk(KERN_DEBUG "Call Reference: %04x\n", chan->callref);
|
|
#endif
|
|
|
|
*(skb_put(*skb, 1)) = 0; /* BC.Length = 0; */
|
|
*(skb_put(*skb, 1)) = 0; /* ConnectedPN.Length = 0 */
|
|
*(skb_put(*skb, 1)) = 0; /* PSA.Length */
|
|
*(skb_put(*skb, 1)) = 0; /* LLC.Length = 0; */
|
|
*(skb_put(*skb, 1)) = 0; /* HLC.Length = 0; */
|
|
*(skb_put(*skb, 1)) = 0; /* UTUS.Length = 0; */
|
|
|
|
return 8;
|
|
}
|
|
|
|
int capi_conn_active_resp(struct pcbit_chan* chan, struct sk_buff **skb)
|
|
{
|
|
/*
|
|
* 2 bytes
|
|
*/
|
|
|
|
if ((*skb = dev_alloc_skb(2)) == NULL) {
|
|
|
|
printk(KERN_WARNING "capi_conn_active_resp: alloc_skb failed\n");
|
|
return -1;
|
|
}
|
|
|
|
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
|
|
|
|
return 2;
|
|
}
|
|
|
|
|
|
int capi_select_proto_req(struct pcbit_chan *chan, struct sk_buff **skb,
|
|
int outgoing)
|
|
{
|
|
|
|
/*
|
|
* 18 bytes
|
|
*/
|
|
|
|
if ((*skb = dev_alloc_skb(18)) == NULL) {
|
|
|
|
printk(KERN_WARNING "capi_select_proto_req: alloc_skb failed\n");
|
|
return -1;
|
|
}
|
|
|
|
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
|
|
|
|
/* Layer2 protocol */
|
|
|
|
switch (chan->proto) {
|
|
case ISDN_PROTO_L2_X75I:
|
|
*(skb_put(*skb, 1)) = 0x05; /* LAPB */
|
|
break;
|
|
case ISDN_PROTO_L2_HDLC:
|
|
*(skb_put(*skb, 1)) = 0x02;
|
|
break;
|
|
case ISDN_PROTO_L2_TRANS:
|
|
/*
|
|
* Voice (a-law)
|
|
*/
|
|
*(skb_put(*skb, 1)) = 0x06;
|
|
break;
|
|
default:
|
|
#ifdef DEBUG
|
|
printk(KERN_DEBUG "Transparent\n");
|
|
#endif
|
|
*(skb_put(*skb, 1)) = 0x03;
|
|
break;
|
|
}
|
|
|
|
*(skb_put(*skb, 1)) = (outgoing ? 0x02 : 0x42); /* Don't ask */
|
|
*(skb_put(*skb, 1)) = 0x00;
|
|
|
|
*((ushort *) skb_put(*skb, 2)) = MRU;
|
|
|
|
|
|
*(skb_put(*skb, 1)) = 0x08; /* Modulo */
|
|
*(skb_put(*skb, 1)) = 0x07; /* Max Window */
|
|
|
|
*(skb_put(*skb, 1)) = 0x01; /* No Layer3 Protocol */
|
|
|
|
/*
|
|
* 2 - layer3 MTU [10]
|
|
* - Modulo [12]
|
|
* - Window
|
|
* - layer1 proto [14]
|
|
* - bitrate
|
|
* - sub-channel [16]
|
|
* - layer1dataformat [17]
|
|
*/
|
|
|
|
memset(skb_put(*skb, 8), 0, 8);
|
|
|
|
return 18;
|
|
}
|
|
|
|
|
|
int capi_activate_transp_req(struct pcbit_chan *chan, struct sk_buff **skb)
|
|
{
|
|
|
|
if ((*skb = dev_alloc_skb(7)) == NULL) {
|
|
|
|
printk(KERN_WARNING "capi_activate_transp_req: alloc_skb failed\n");
|
|
return -1;
|
|
}
|
|
|
|
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
|
|
|
|
|
|
*(skb_put(*skb, 1)) = chan->layer2link; /* Layer2 id */
|
|
*(skb_put(*skb, 1)) = 0x00; /* Transmit by default */
|
|
|
|
*((ushort *) skb_put(*skb, 2)) = MRU;
|
|
|
|
*(skb_put(*skb, 1)) = 0x01; /* Enables reception*/
|
|
|
|
return 7;
|
|
}
|
|
|
|
int capi_tdata_req(struct pcbit_chan* chan, struct sk_buff *skb)
|
|
{
|
|
ushort data_len;
|
|
|
|
|
|
/*
|
|
* callref - 2
|
|
* layer2link - 1
|
|
* wBlockLength - 2
|
|
* data - 4
|
|
* sernum - 1
|
|
*/
|
|
|
|
data_len = skb->len;
|
|
|
|
if(skb_headroom(skb) < 10)
|
|
{
|
|
printk(KERN_CRIT "No headspace (%u) on headroom %p for capi header\n", skb_headroom(skb), skb);
|
|
}
|
|
else
|
|
{
|
|
skb_push(skb, 10);
|
|
}
|
|
|
|
*((u16 *) (skb->data)) = chan->callref;
|
|
skb->data[2] = chan->layer2link;
|
|
*((u16 *) (skb->data + 3)) = data_len;
|
|
|
|
chan->s_refnum = (chan->s_refnum + 1) % 8;
|
|
*((u32 *) (skb->data + 5)) = chan->s_refnum;
|
|
|
|
skb->data[9] = 0; /* HDLC frame number */
|
|
|
|
return 10;
|
|
}
|
|
|
|
int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff ** skb)
|
|
|
|
{
|
|
if ((*skb = dev_alloc_skb(4)) == NULL) {
|
|
|
|
printk(KERN_WARNING "capi_tdata_resp: alloc_skb failed\n");
|
|
return -1;
|
|
}
|
|
|
|
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
|
|
|
|
*(skb_put(*skb, 1)) = chan->layer2link;
|
|
*(skb_put(*skb, 1)) = chan->r_refnum;
|
|
|
|
return (*skb)->len;
|
|
}
|
|
|
|
int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause)
|
|
{
|
|
|
|
if ((*skb = dev_alloc_skb(6)) == NULL) {
|
|
|
|
printk(KERN_WARNING "capi_disc_req: alloc_skb failed\n");
|
|
return -1;
|
|
}
|
|
|
|
*((ushort*) skb_put(*skb, 2) ) = callref;
|
|
|
|
*(skb_put(*skb, 1)) = 2; /* Cause.Length = 2; */
|
|
*(skb_put(*skb, 1)) = 0x80;
|
|
*(skb_put(*skb, 1)) = 0x80 | cause;
|
|
|
|
/*
|
|
* Change it: we should send 'Sic transit gloria Mundi' here ;-)
|
|
*/
|
|
|
|
*(skb_put(*skb, 1)) = 0; /* UTUS.Length = 0; */
|
|
|
|
return 6;
|
|
}
|
|
|
|
int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb)
|
|
{
|
|
if ((*skb = dev_alloc_skb(2)) == NULL) {
|
|
|
|
printk(KERN_WARNING "capi_disc_resp: alloc_skb failed\n");
|
|
return -1;
|
|
}
|
|
|
|
*((ushort*) skb_put(*skb, 2)) = chan->callref;
|
|
|
|
return 2;
|
|
}
|
|
|
|
|
|
/*
|
|
* Decoding of CAPI messages
|
|
*
|
|
*/
|
|
|
|
int capi_decode_conn_ind(struct pcbit_chan * chan,
|
|
struct sk_buff *skb,
|
|
struct callb_data *info)
|
|
{
|
|
int CIlen, len;
|
|
|
|
/* Call Reference [CAPI] */
|
|
chan->callref = *((ushort*) skb->data);
|
|
skb_pull(skb, 2);
|
|
|
|
#ifdef DEBUG
|
|
printk(KERN_DEBUG "Call Reference: %04x\n", chan->callref);
|
|
#endif
|
|
|
|
/* Channel Identification */
|
|
|
|
/* Expect
|
|
Len = 1
|
|
Octect 3 = 0100 10CC - [ 7 Basic, 4 , 2-1 chan ]
|
|
*/
|
|
|
|
CIlen = skb->data[0];
|
|
#ifdef DEBUG
|
|
if (CIlen == 1) {
|
|
|
|
if ( ((skb->data[1]) & 0xFC) == 0x48 )
|
|
printk(KERN_DEBUG "decode_conn_ind: chan ok\n");
|
|
printk(KERN_DEBUG "phyChan = %d\n", skb->data[1] & 0x03);
|
|
}
|
|
else
|
|
printk(KERN_DEBUG "conn_ind: CIlen = %d\n", CIlen);
|
|
#endif
|
|
skb_pull(skb, CIlen + 1);
|
|
|
|
/* Calling Party Number */
|
|
/* An "additional service" as far as Portugal Telecom is concerned */
|
|
|
|
len = skb->data[0];
|
|
|
|
if (len > 0) {
|
|
int count = 1;
|
|
|
|
#ifdef DEBUG
|
|
printk(KERN_DEBUG "CPN: Octect 3 %02x\n", skb->data[1]);
|
|
#endif
|
|
if ((skb->data[1] & 0x80) == 0)
|
|
count = 2;
|
|
|
|
if (!(info->data.setup.CallingPN = kmalloc(len - count + 1, GFP_ATOMIC)))
|
|
return -1;
|
|
|
|
memcpy(info->data.setup.CallingPN, skb->data + count + 1,
|
|
len - count);
|
|
info->data.setup.CallingPN[len - count] = 0;
|
|
|
|
}
|
|
else {
|
|
info->data.setup.CallingPN = NULL;
|
|
printk(KERN_DEBUG "NULL CallingPN\n");
|
|
}
|
|
|
|
skb_pull(skb, len + 1);
|
|
|
|
/* Calling Party Subaddress */
|
|
skb_pull(skb, skb->data[0] + 1);
|
|
|
|
/* Called Party Number */
|
|
|
|
len = skb->data[0];
|
|
|
|
if (len > 0) {
|
|
int count = 1;
|
|
|
|
if ((skb->data[1] & 0x80) == 0)
|
|
count = 2;
|
|
|
|
if (!(info->data.setup.CalledPN = kmalloc(len - count + 1, GFP_ATOMIC)))
|
|
return -1;
|
|
|
|
memcpy(info->data.setup.CalledPN, skb->data + count + 1,
|
|
len - count);
|
|
info->data.setup.CalledPN[len - count] = 0;
|
|
|
|
}
|
|
else {
|
|
info->data.setup.CalledPN = NULL;
|
|
printk(KERN_DEBUG "NULL CalledPN\n");
|
|
}
|
|
|
|
skb_pull(skb, len + 1);
|
|
|
|
/* Called Party Subaddress */
|
|
skb_pull(skb, skb->data[0] + 1);
|
|
|
|
/* LLC */
|
|
skb_pull(skb, skb->data[0] + 1);
|
|
|
|
/* HLC */
|
|
skb_pull(skb, skb->data[0] + 1);
|
|
|
|
/* U2U */
|
|
skb_pull(skb, skb->data[0] + 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* returns errcode
|
|
*/
|
|
|
|
int capi_decode_conn_conf(struct pcbit_chan * chan, struct sk_buff *skb,
|
|
int *complete)
|
|
{
|
|
int errcode;
|
|
|
|
chan->callref = *((ushort *) skb->data); /* Update CallReference */
|
|
skb_pull(skb, 2);
|
|
|
|
errcode = *((ushort *) skb->data); /* read errcode */
|
|
skb_pull(skb, 2);
|
|
|
|
*complete = *(skb->data);
|
|
skb_pull(skb, 1);
|
|
|
|
/* FIX ME */
|
|
/* This is actually a firmware bug */
|
|
if (!*complete)
|
|
{
|
|
printk(KERN_DEBUG "complete=%02x\n", *complete);
|
|
*complete = 1;
|
|
}
|
|
|
|
|
|
/* Optional Bearer Capability */
|
|
skb_pull(skb, *(skb->data) + 1);
|
|
|
|
/* Channel Identification */
|
|
skb_pull(skb, *(skb->data) + 1);
|
|
|
|
/* High Layer Compatibility follows */
|
|
skb_pull(skb, *(skb->data) + 1);
|
|
|
|
return errcode;
|
|
}
|
|
|
|
int capi_decode_conn_actv_ind(struct pcbit_chan * chan, struct sk_buff *skb)
|
|
{
|
|
ushort len;
|
|
#ifdef DEBUG
|
|
char str[32];
|
|
#endif
|
|
|
|
/* Yet Another Bearer Capability */
|
|
skb_pull(skb, *(skb->data) + 1);
|
|
|
|
|
|
/* Connected Party Number */
|
|
len=*(skb->data);
|
|
|
|
#ifdef DEBUG
|
|
if (len > 1 && len < 31) {
|
|
memcpy(str, skb->data + 2, len - 1);
|
|
str[len] = 0;
|
|
printk(KERN_DEBUG "Connected Party Number: %s\n", str);
|
|
}
|
|
else
|
|
printk(KERN_DEBUG "actv_ind CPN len = %d\n", len);
|
|
#endif
|
|
|
|
skb_pull(skb, len + 1);
|
|
|
|
/* Connected Subaddress */
|
|
skb_pull(skb, *(skb->data) + 1);
|
|
|
|
/* Low Layer Capability */
|
|
skb_pull(skb, *(skb->data) + 1);
|
|
|
|
/* High Layer Capability */
|
|
skb_pull(skb, *(skb->data) + 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int capi_decode_conn_actv_conf(struct pcbit_chan * chan, struct sk_buff *skb)
|
|
{
|
|
ushort errcode;
|
|
|
|
errcode = *((ushort*) skb->data);
|
|
skb_pull(skb, 2);
|
|
|
|
/* Channel Identification
|
|
skb_pull(skb, skb->data[0] + 1);
|
|
*/
|
|
return errcode;
|
|
}
|
|
|
|
|
|
int capi_decode_sel_proto_conf(struct pcbit_chan *chan, struct sk_buff *skb)
|
|
{
|
|
ushort errcode;
|
|
|
|
chan->layer2link = *(skb->data);
|
|
skb_pull(skb, 1);
|
|
|
|
errcode = *((ushort*) skb->data);
|
|
skb_pull(skb, 2);
|
|
|
|
return errcode;
|
|
}
|
|
|
|
int capi_decode_actv_trans_conf(struct pcbit_chan *chan, struct sk_buff *skb)
|
|
{
|
|
ushort errcode;
|
|
|
|
if (chan->layer2link != *(skb->data) )
|
|
printk("capi_decode_actv_trans_conf: layer2link doesn't match\n");
|
|
|
|
skb_pull(skb, 1);
|
|
|
|
errcode = *((ushort*) skb->data);
|
|
skb_pull(skb, 2);
|
|
|
|
return errcode;
|
|
}
|
|
|
|
int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb)
|
|
{
|
|
ushort len;
|
|
#ifdef DEBUG
|
|
int i;
|
|
#endif
|
|
/* Cause */
|
|
|
|
len = *(skb->data);
|
|
skb_pull(skb, 1);
|
|
|
|
#ifdef DEBUG
|
|
|
|
for (i=0; i<len; i++)
|
|
printk(KERN_DEBUG "Cause Octect %d: %02x\n", i+3,
|
|
*(skb->data + i));
|
|
#endif
|
|
|
|
skb_pull(skb, len);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
int capi_decode_debug_188(u_char *hdr, ushort hdrlen)
|
|
{
|
|
char str[64];
|
|
int len;
|
|
|
|
len = hdr[0];
|
|
|
|
if (len < 64 && len == hdrlen - 1) {
|
|
memcpy(str, hdr + 1, hdrlen - 1);
|
|
str[hdrlen - 1] = 0;
|
|
printk("%s\n", str);
|
|
}
|
|
else
|
|
printk("debug message incorrect\n");
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|