diff options
Diffstat (limited to 'drivers/isdn/pcbit/capi.c')
-rw-r--r-- | drivers/isdn/pcbit/capi.c | 649 |
1 files changed, 0 insertions, 649 deletions
diff --git a/drivers/isdn/pcbit/capi.c b/drivers/isdn/pcbit/capi.c deleted file mode 100644 index 4e3cbf857d60..000000000000 --- a/drivers/isdn/pcbit/capi.c +++ /dev/null @@ -1,649 +0,0 @@ -/* - * 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; - - skb_copy_from_linear_data_offset(skb, count + 1, - info->data.setup.CallingPN, - 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; - - skb_copy_from_linear_data_offset(skb, count + 1, - info->data.setup.CalledPN, - 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) { - skb_copy_from_linear_data_offset(skb, 2, str, 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 |