Commit 6a7fc460 authored by Kai Germaschewski's avatar Kai Germaschewski

ISDN: State machines for the link layer

Since we unfortunately cannot rely on the hardware drivers to get
their states always correct, have the common layer keep track of the
states and sanitize them before passing them on to applications
as network interfaces / ttyIs.
parent 83a64b26
......@@ -564,7 +564,7 @@ isdn_audio_eval_dtmf(modem_info * info)
cli();
di = isdn_slot_driver(info->isdn_slot);
ch = isdn_slot_channel(info->isdn_slot);
isdn_drv_queue_tail(di, ch, skb, 2);
isdn_slot_queue_tail(info->isdn_slot, skb, 2);
restore_flags(flags);
/* Schedule dequeuing */
if ((dev->modempoll) && (info->rcvsched))
......@@ -683,7 +683,7 @@ isdn_audio_put_dle_code(modem_info * info, u_char code)
cli();
di = isdn_slot_driver(info->isdn_slot);
ch = isdn_slot_channel(info->isdn_slot);
isdn_drv_queue_tail(di, ch, skb, 2);
isdn_slot_queue_tail(info->isdn_slot, skb, 2);
restore_flags(flags);
/* Schedule dequeuing */
if ((dev->modempoll) && (info->rcvsched))
......
This diff is collapsed.
......@@ -19,7 +19,7 @@
#undef ISDN_DEBUG_MODEM_DUMP
#undef ISDN_DEBUG_MODEM_VOICE
#undef ISDN_DEBUG_AT
#define ISDN_DEBUG_NET_DUMP
#undef ISDN_DEBUG_NET_DUMP
#define ISDN_DEBUG_NET_DIAL
#define ISDN_DEBUG_NET_ICALL
#define ISDN_DEBUG_STATCALLB
......@@ -66,7 +66,7 @@ extern int isdn_msncmp( const char *, const char *);
#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
extern void isdn_dumppkt(char *, u_char *, int, int);
#else
static inline void isdn_dumppkt(char *s, u_char *d, int l, int m) { }
static inline void isdn_dumppkt(char *s, char *ss, u_char *d, int l, int m) { }
#endif
struct dial_info {
......@@ -95,12 +95,13 @@ extern void isdn_slot_set_usage(int slot, int usage);
extern char *isdn_slot_num(int slot);
extern int isdn_slot_m_idx(int slot);
extern void isdn_slot_set_m_idx(int slot, int midx);
extern void isdn_slot_set_priv(int sl, void *);
extern void isdn_slot_set_priv(int sl, void *priv, int (*stat_cb)(int sl, isdn_ctrl *ctrl), int (*recv_cb)(int sl, struct sk_buff *skb));
extern void *isdn_slot_priv(int sl);
extern int isdn_hard_header_len(void);
int isdn_drv_queue_empty(int di, int ch);
void isdn_drv_queue_tail(int di, int ch, struct sk_buff *skb, int len);
int isdn_slot_queue_empty(int sl);
void isdn_slot_queue_tail(int sl, struct sk_buff *skb, int len);
void isdn_slot_queue_purge(int sl);
int isdn_drv_maxbufsize(int di);
int isdn_drv_writebuf_skb(int di, int ch, int x, struct sk_buff *skb);
int isdn_drv_hdrlen(int di);
......
......@@ -264,7 +264,7 @@ static int
isdn_net_bind(isdn_net_dev *idev, isdn_net_ioctl_cfg *cfg)
{
isdn_net_local *mlp = idev->mlp;
int i, retval;
int retval;
int drvidx = -1;
int chidx = -1;
char drvid[25];
......@@ -287,14 +287,7 @@ isdn_net_bind(isdn_net_dev *idev, isdn_net_ioctl_cfg *cfg)
/* The channel-number is appended to the driver-Id with a comma */
*c = 0;
chidx = simple_strtol(c + 1, NULL, 10);
for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
/* Lookup driver-Id in array */
if (!strcmp(dev->drvid[i], drvid)) {
drvidx = i;
break;
}
}
drvidx = isdn_drv_lookup(drvid);
if (drvidx == -1 || chidx == -1) {
/* Either driver-Id or channel-number invalid */
retval = -ENODEV;
......@@ -380,7 +373,6 @@ isdn_net_addif(char *name, isdn_net_local *mlp)
idev->pre_channel = -1;
idev->exclusive = -1;
idev->ipppd = NULL;
idev->pppbind = -1;
init_timer(&idev->dial_timer);
......@@ -547,8 +539,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg *cfg)
{
isdn_net_dev *idev = isdn_net_findif(cfg->name);
isdn_net_local *mlp;
ulong features;
int i, retval;
int retval;
if (!idev)
return -ENODEV;
......@@ -561,19 +552,6 @@ isdn_net_setcfg(isdn_net_ioctl_cfg *cfg)
retval = -EBUSY;
goto out;
}
/* See if any registered driver supports the features we want */
features = ((1 << cfg->l2_proto) << ISDN_FEATURE_L2_SHIFT) |
((1 << cfg->l3_proto) << ISDN_FEATURE_L3_SHIFT);
for (i = 0; i < ISDN_MAX_DRIVERS; i++)
if (dev->drv[i] &&
(dev->drv[i]->interface->features & features) == features)
break;
if (i == ISDN_MAX_DRIVERS) {
printk(KERN_WARNING "isdn_net: No driver with selected features\n");
retval = -ENODEV;
goto out;
}
retval = isdn_net_set_encap(mlp, cfg->p_encap);
if (retval)
......@@ -667,7 +645,7 @@ isdn_net_getcfg(isdn_net_ioctl_cfg *cfg)
strcpy(cfg->eaz, mlp->msn);
cfg->exclusive = idev->exclusive >= 0;
if (idev->pre_device >= 0) {
sprintf(cfg->drvid, "%s,%d", dev->drvid[idev->pre_device],
sprintf(cfg->drvid, "%s,%d", isdn_drv_drvid(idev->pre_device),
idev->pre_channel);
} else {
cfg->drvid[0] = '\0';
......@@ -1224,7 +1202,7 @@ isdn_net_unbind_channel(isdn_net_dev *idev)
if (mlp->ops->unbind)
mlp->ops->unbind(idev);
isdn_slot_set_idev(idev->isdn_slot, NULL);
isdn_slot_set_priv(idev->isdn_slot, NULL, NULL, NULL);
skb_queue_purge(&idev->super_tx_queue);
......@@ -1239,6 +1217,9 @@ isdn_net_unbind_channel(isdn_net_dev *idev)
}
}
static int isdn_net_stat_callback(int, isdn_ctrl *);
static int isdn_net_rcv_skb(int, struct sk_buff *);
/*
* Assign an ISDN-channel to a net-interface
*/
......@@ -1249,7 +1230,8 @@ isdn_net_bind_channel(isdn_net_dev *idev, int slot)
int retval = 0;
idev->isdn_slot = slot;
isdn_slot_set_idev(idev->isdn_slot, idev);
isdn_slot_set_priv(idev->isdn_slot, idev, isdn_net_stat_callback,
isdn_net_rcv_skb);
if (mlp->ops->bind)
retval = mlp->ops->bind(idev);
......@@ -1889,10 +1871,10 @@ isdn_net_hangup(isdn_net_dev *idev)
* isdn_status_callback, which itself is called from the low-level driver.
* Return: 1 = event handled, 0 = not handled
*/
int
static int
isdn_net_stat_callback(int idx, isdn_ctrl *c)
{
isdn_net_dev *idev = isdn_slot_idev(idx);
isdn_net_dev *idev = isdn_slot_priv(idx);
if (!idev) {
return 0;
......@@ -2285,10 +2267,10 @@ isdn_net_write_super(isdn_net_dev *idev, struct sk_buff *skb)
* interface. If found, deliver packet to receiver-function and return 1,
* else return 0.
*/
int
static int
isdn_net_rcv_skb(int idx, struct sk_buff *skb)
{
isdn_net_dev *idev = isdn_slot_idev(idx);
isdn_net_dev *idev = isdn_slot_priv(idx);
isdn_net_local *mlp;
if (!idev) {
......@@ -2359,7 +2341,5 @@ isdn_net_lib_init(void)
void
isdn_net_lib_exit(void)
{
fsm_free(&isdn_net_fsm);
}
......@@ -50,9 +50,7 @@ void isdn_net_lib_init(void);
void isdn_net_lib_exit(void);
void isdn_net_hangup_all(void);
int isdn_net_ioctl(struct inode *, struct file *, uint, ulong);
int isdn_net_stat_callback(int, isdn_ctrl *);
int isdn_net_find_icall(int, int, int, setup_parm *);
int isdn_net_rcv_skb(int, struct sk_buff *);
/* provided for interface types to use */
void isdn_net_writebuf_skb(isdn_net_dev *, struct sk_buff *skb);
......
......@@ -43,7 +43,7 @@ isdn_ppp_set_compressor(isdn_net_dev *idev, struct isdn_ppp_comp_data *);
* idev->ipppd is safe without further locking.
*/
#define IPPPD_DEBUG
#undef IPPPD_DEBUG
#ifdef IPPPD_DEBUG
#define ipppd_debug(i, fmt, arg...) \
......
......@@ -165,15 +165,6 @@ ippp_mp_receive(isdn_net_dev *idev, struct sk_buff *skb, u16 proto)
#define MP_GT(a,b) ((b-a)&MP_LONGSEQ_MAXBIT)
#define MP_GE(a,b) !((a-b)&MP_LONGSEQ_MAXBIT)
static void
print_recv_pkt(int slot, struct sk_buff *skb)
{
printk(KERN_DEBUG "mp_recv: %d/%d -> %02x %02x %02x %02x %02x %02x\n",
slot, skb->len,
skb->data[0], skb->data[1], skb->data[2],
skb->data[3], skb->data[4], skb->data[5]);
}
#define MP_SEQUENCE(skb) (skb)->priority
#define MP_FLAGS(skb) (skb)->cb[0]
......@@ -237,7 +228,6 @@ mp_complete_seq(isdn_net_local *lp, struct sk_buff *b, struct sk_buff *e)
if (b->next == e) {
/* sequence with only one frag */
HERE;
skb_unlink(b);
return b;
}
......@@ -320,8 +310,6 @@ mp_receive(isdn_net_dev *idev, struct sk_buff *skb)
u32 seq;
u16 proto;
print_recv_pkt(-1, skb);
if (skb->len < (inl_ppp->mp_cfg & SC_IN_SHORT_SEQ ? 2 : 4))
goto drop;
......
......@@ -7,7 +7,8 @@
* of the GNU General Public License, incorporated herein by reference.
*/
#undef ISDN_TTY_STAT_DEBUG
#define ISDN_TTY_STAT_DEBUG
#define ISDN_DEBUG_MODEM_HUP
#include <linux/config.h>
#include <linux/isdn.h>
......@@ -30,6 +31,7 @@ static void isdn_tty_modem_reset_regs(modem_info *, int);
static void isdn_tty_cmd_ATA(modem_info *);
static void isdn_tty_flush_buffer(struct tty_struct *);
static void isdn_tty_modem_result(int, modem_info *);
static int isdn_tty_stat_callback(int i, isdn_ctrl *c);
#ifdef CONFIG_ISDN_AUDIO
static int isdn_tty_countDLE(unsigned char *, int);
#endif
......@@ -167,21 +169,16 @@ isdn_tty_readmodem(void)
isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0);
}
int
isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
static int
isdn_tty_rcv_skb(int i, struct sk_buff *skb)
{
ulong flags;
int midx;
#ifdef CONFIG_ISDN_AUDIO
int ifmt;
#endif
modem_info *info;
if ((midx = isdn_slot_m_idx(i)) < 0) {
/* if midx is invalid, packet is not for tty */
return 0;
}
info = &dev->mdm.info[midx];
info = isdn_slot_priv(i);
#ifdef CONFIG_ISDN_AUDIO
ifmt = 1;
......@@ -264,7 +261,7 @@ isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
/* Try to deliver directly via tty-flip-buf if queue is empty */
save_flags(flags);
cli();
if (isdn_drv_queue_empty(di, channel))
if (isdn_slot_queue_empty(i))
if (isdn_tty_try_read(info, skb)) {
restore_flags(flags);
return 1;
......@@ -272,7 +269,7 @@ isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
/* Direct deliver failed or queue wasn't empty.
* Queue up for later dequeueing via timer-irq.
*/
isdn_drv_queue_tail(di, channel, skb, skb->len
isdn_slot_queue_tail(i, skb, skb->len
#ifdef CONFIG_ISDN_AUDIO
+ ISDN_AUDIO_SKB_DLECOUNT(skb)
#endif
......@@ -656,8 +653,10 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m)
.msn = m->msn,
.phone = n,
};
info->isdn_slot = i;
isdn_slot_set_m_idx(i, info->line);
isdn_slot_set_priv(i, info, isdn_tty_stat_callback, isdn_tty_rcv_skb);
info->last_dir = 1;
info->last_l2 = l2;
strcpy(info->last_num, n);
......@@ -739,7 +738,7 @@ isdn_tty_modem_hup(modem_info * info, int local)
isdn_slot_all_eaz(slot);
info->emu.mdmreg[REG_RINGCNT] = 0;
isdn_slot_free(slot);
isdn_slot_set_m_idx(slot, -1);
isdn_slot_set_priv(slot, NULL, NULL, NULL);
info->isdn_slot = -1;
}
......@@ -833,6 +832,7 @@ isdn_tty_resume(char *id, modem_info * info, atemu * m)
} else {
info->isdn_slot = i;
isdn_slot_set_m_idx(i, info->line);
isdn_slot_set_priv(i, info, isdn_tty_stat_callback, isdn_tty_rcv_skb);
isdn_slot_set_usage(i, isdn_slot_usage(i) | ISDN_USAGE_OUTGOING);
info->last_dir = 1;
// strcpy(info->last_num, n);
......@@ -909,6 +909,7 @@ isdn_tty_send_msg(modem_info * info, atemu * m, char *msg)
} else {
info->isdn_slot = i;
isdn_slot_set_m_idx(i, info->line);
isdn_slot_set_priv(i, info, isdn_tty_stat_callback, isdn_tty_rcv_skb);
isdn_slot_set_usage(i, isdn_slot_usage(i) | ISDN_USAGE_OUTGOING);
info->last_dir = 1;
restore_flags(flags);
......@@ -1106,7 +1107,10 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co
c = count;
if (c > info->xmit_size - info->xmit_count)
c = info->xmit_size - info->xmit_count;
di = isdn_slot_driver(info->isdn_slot);
if (info->isdn_slot >= 0)
di = isdn_slot_driver(info->isdn_slot);
else
di = -1;
if (di >= 0 && c > isdn_drv_maxbufsize(di))
c = isdn_drv_maxbufsize(di);
if (c <= 0)
......@@ -2190,6 +2194,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
if (!matchret) { /* EAZ is matching */
info->isdn_slot = idx;
isdn_slot_set_m_idx(idx, info->line);
isdn_slot_set_priv(idx, info, isdn_tty_stat_callback, isdn_tty_rcv_skb);
strcpy(isdn_slot_num(idx), nr);
strcpy(info->emu.cpn, eaz);
info->emu.mdmreg[REG_SI1I] = si2bit[si1];
......@@ -2216,17 +2221,14 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
#define TTY_IS_ACTIVE(info) \
(info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE))
int
static int
isdn_tty_stat_callback(int i, isdn_ctrl *c)
{
int mi;
modem_info *info;
char *e;
if (i < 0)
return 0;
if ((mi = isdn_slot_m_idx(i)) >= 0) {
info = &dev->mdm.info[mi];
info = isdn_slot_priv(i);
if (1) {
switch (c->command) {
case ISDN_STAT_CINF:
printk(KERN_DEBUG "CHARGEINFO on ttyI%d: %ld %s\n", info->line, c->arg, c->parm.num);
......@@ -2437,9 +2439,13 @@ isdn_tty_at_cout(char *msg, modem_info * info)
/* use queue instead of direct flip, if online and */
/* data is in queue or flip buffer is full */
di = isdn_slot_driver(info->isdn_slot); ch = isdn_slot_channel(info->isdn_slot);
if (info->isdn_slot >= 0) {
di = isdn_slot_driver(info->isdn_slot); ch = isdn_slot_channel(info->isdn_slot);
} else {
di = -1; ch = -1;
}
if ((info->online) && (((tty->flip.count + strlen(msg)) >= TTY_FLIPBUF_SIZE) ||
(!isdn_drv_queue_empty(di, ch)))) {
(!isdn_slot_queue_empty(info->isdn_slot)))) {
skb = alloc_skb(strlen(msg)
#ifdef CONFIG_ISDN_AUDIO
+ sizeof(isdn_audio_skb)
......@@ -2482,7 +2488,7 @@ isdn_tty_at_cout(char *msg, modem_info * info)
}
}
if (skb) {
isdn_drv_queue_tail(di, ch, skb, skb->len);
isdn_slot_queue_tail(info->isdn_slot, skb, skb->len);
restore_flags(flags);
/* Schedule dequeuing */
if ((dev->modempoll) && (info->rcvsched))
......
......@@ -106,8 +106,6 @@ extern int isdn_tty_init(void);
extern void isdn_tty_readmodem(void);
extern int isdn_tty_find_icall(int, int, setup_parm *);
extern void isdn_tty_cleanup_xmit(modem_info *);
extern int isdn_tty_stat_callback(int, isdn_ctrl *);
extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *);
extern int isdn_tty_capi_facility(capi_msg *cm);
extern void isdn_tty_at_cout(char *, modem_info *);
extern void isdn_tty_modem_hup(modem_info *, int);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment