/* * Callbacks for the FSM * * 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. */ /* * Fix: 19981230 - Carlos Morgado <chbm@techie.com> * Port of Nelson Escravana's <nelson.escravana@usa.net> fix to CalledPN * NULL pointer dereference in cb_in_1 (originally fixed in 2.0) */ #include <linux/string.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/mm.h> #include <linux/skbuff.h> #include <asm/io.h> #include <linux/isdnif.h> #include "pcbit.h" #include "layer2.h" #include "edss1.h" #include "callbacks.h" #include "capi.h" ushort last_ref_num = 1; /* * send_conn_req * */ void cb_out_1(struct pcbit_dev * dev, struct pcbit_chan* chan, struct callb_data *cbdata) { struct sk_buff *skb; int len; ushort refnum; #ifdef DEBUG printk(KERN_DEBUG "Called Party Number: %s\n", cbdata->data.setup.CalledPN); #endif /* * hdr - kmalloc in capi_conn_req * - kfree when msg has been sent */ if ((len = capi_conn_req(cbdata->data.setup.CalledPN, &skb, chan->proto)) < 0) { printk("capi_conn_req failed\n"); return; } refnum = last_ref_num++ & 0x7fffU; chan->callref = 0; chan->layer2link = 0; chan->snum = 0; chan->s_refnum = refnum; pcbit_l2_write(dev, MSG_CONN_REQ, refnum, skb, len); } /* * rcv CONNECT * will go into ACTIVE state * send CONN_ACTIVE_RESP * send Select protocol request */ void cb_out_2(struct pcbit_dev * dev, struct pcbit_chan* chan, struct callb_data *data) { isdn_ctrl ictl; struct sk_buff *skb; int len; ushort refnum; if ((len=capi_conn_active_resp(chan, &skb)) < 0) { printk("capi_conn_active_req failed\n"); return; } refnum = last_ref_num++ & 0x7fffU; chan->s_refnum = refnum; pcbit_l2_write(dev, MSG_CONN_ACTV_RESP, refnum, skb, len); ictl.command = ISDN_STAT_DCONN; ictl.driver=dev->id; ictl.arg=chan->id; dev->dev_if->statcallb(&ictl); /* ACTIVE D-channel */ /* Select protocol */ if ((len=capi_select_proto_req(chan, &skb, 1 /*outgoing*/)) < 0) { printk("capi_select_proto_req failed\n"); return; } refnum = last_ref_num++ & 0x7fffU; chan->s_refnum = refnum; pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len); } /* * Incoming call received * inform user */ void cb_in_1(struct pcbit_dev * dev, struct pcbit_chan* chan, struct callb_data *cbdata) { isdn_ctrl ictl; unsigned short refnum; struct sk_buff *skb; int len; ictl.command = ISDN_STAT_ICALL; ictl.driver=dev->id; ictl.arg=chan->id; /* * ictl.num >= strlen() + strlen() + 5 */ if (cbdata->data.setup.CallingPN == NULL) { printk(KERN_DEBUG "NULL CallingPN to phone; using 0\n"); strcpy(ictl.parm.setup.phone, "0"); } else { strcpy(ictl.parm.setup.phone, cbdata->data.setup.CallingPN); } if (cbdata->data.setup.CalledPN == NULL) { printk(KERN_DEBUG "NULL CalledPN to eazmsn; using 0\n"); strcpy(ictl.parm.setup.eazmsn, "0"); } else { strcpy(ictl.parm.setup.eazmsn, cbdata->data.setup.CalledPN); } ictl.parm.setup.si1 = 7; ictl.parm.setup.si2 = 0; ictl.parm.setup.plan = 0; ictl.parm.setup.screen = 0; #ifdef DEBUG printk(KERN_DEBUG "statstr: %s\n", ictl.num); #endif dev->dev_if->statcallb(&ictl); if ((len=capi_conn_resp(chan, &skb)) < 0) { printk(KERN_DEBUG "capi_conn_resp failed\n"); return; } refnum = last_ref_num++ & 0x7fffU; chan->s_refnum = refnum; pcbit_l2_write(dev, MSG_CONN_RESP, refnum, skb, len); } /* * user has replied * open the channel * send CONNECT message CONNECT_ACTIVE_REQ in CAPI */ void cb_in_2(struct pcbit_dev * dev, struct pcbit_chan* chan, struct callb_data *data) { unsigned short refnum; struct sk_buff *skb; int len; if ((len = capi_conn_active_req(chan, &skb)) < 0) { printk(KERN_DEBUG "capi_conn_active_req failed\n"); return; } refnum = last_ref_num++ & 0x7fffU; chan->s_refnum = refnum; printk(KERN_DEBUG "sending MSG_CONN_ACTV_REQ\n"); pcbit_l2_write(dev, MSG_CONN_ACTV_REQ, refnum, skb, len); } /* * CONN_ACK arrived * start b-proto selection * */ void cb_in_3(struct pcbit_dev * dev, struct pcbit_chan* chan, struct callb_data *data) { unsigned short refnum; struct sk_buff *skb; int len; if ((len = capi_select_proto_req(chan, &skb, 0 /*incoming*/)) < 0) { printk("capi_select_proto_req failed\n"); return; } refnum = last_ref_num++ & 0x7fffU; chan->s_refnum = refnum; pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len); } /* * Received disconnect ind on active state * send disconnect resp * send msg to user */ void cb_disc_1(struct pcbit_dev * dev, struct pcbit_chan* chan, struct callb_data *data) { struct sk_buff *skb; int len; ushort refnum; isdn_ctrl ictl; if ((len = capi_disc_resp(chan, &skb)) < 0) { printk("capi_disc_resp failed\n"); return; } refnum = last_ref_num++ & 0x7fffU; chan->s_refnum = refnum; pcbit_l2_write(dev, MSG_DISC_RESP, refnum, skb, len); ictl.command = ISDN_STAT_BHUP; ictl.driver=dev->id; ictl.arg=chan->id; dev->dev_if->statcallb(&ictl); } /* * User HANGUP on active/call proceeding state * send disc.req */ void cb_disc_2(struct pcbit_dev * dev, struct pcbit_chan* chan, struct callb_data *data) { struct sk_buff *skb; int len; ushort refnum; if ((len = capi_disc_req(chan->callref, &skb, CAUSE_NORMAL)) < 0) { printk("capi_disc_req failed\n"); return; } refnum = last_ref_num++ & 0x7fffU; chan->s_refnum = refnum; pcbit_l2_write(dev, MSG_DISC_REQ, refnum, skb, len); } /* * Disc confirm received send BHUP * Problem: when the HL driver sends the disc req itself * LL receives BHUP */ void cb_disc_3(struct pcbit_dev * dev, struct pcbit_chan* chan, struct callb_data *data) { isdn_ctrl ictl; ictl.command = ISDN_STAT_BHUP; ictl.driver=dev->id; ictl.arg=chan->id; dev->dev_if->statcallb(&ictl); } void cb_notdone(struct pcbit_dev * dev, struct pcbit_chan* chan, struct callb_data *data) { } /* * send activate b-chan protocol */ void cb_selp_1(struct pcbit_dev * dev, struct pcbit_chan* chan, struct callb_data *data) { struct sk_buff *skb; int len; ushort refnum; if ((len = capi_activate_transp_req(chan, &skb)) < 0) { printk("capi_conn_activate_transp_req failed\n"); return; } refnum = last_ref_num++ & 0x7fffU; chan->s_refnum = refnum; pcbit_l2_write(dev, MSG_ACT_TRANSP_REQ, refnum, skb, len); } /* * Inform User that the B-channel is available */ void cb_open(struct pcbit_dev * dev, struct pcbit_chan* chan, struct callb_data *data) { isdn_ctrl ictl; ictl.command = ISDN_STAT_BCONN; ictl.driver=dev->id; ictl.arg=chan->id; dev->dev_if->statcallb(&ictl); }