Commit b14ebcfc authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://thebsh.namesys.com/bk/reiser3-linux-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents cb7ada82 16b39f5f
......@@ -247,6 +247,17 @@ ChangeLog
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
2.0.24:
- Small internal cleanups.
- Support for sendfile system call. (Christoph Hellwig)
2.0.23:
- Massive internal locking changes to mft record locking. Fixes
various race conditions and deadlocks.
- Fix ntfs over loopback for compressed files by adding an
optimization barrier. (gcc was screwing up otherwise ?)
Thanks go to Christoph Hellwig for pointing these two out:
- Remove now unused function fs/ntfs/malloc.h::vmalloc_nofs().
- Fix ntfs_free() for ia64 and parisc.
2.0.22:
- Small internal cleanups.
2.0.21:
......
......@@ -138,7 +138,7 @@ typedef struct actcapi_ncpd {
typedef struct actcapi_msg {
actcapi_msghdr hdr;
union msg {
union {
__u16 manuf_msg;
struct manufacturer_req_net {
__u16 manuf_msg;
......
......@@ -564,8 +564,8 @@ isdn_audio_eval_dtmf(modem_info * info)
ISDN_AUDIO_SKB_LOCK(skb) = 0;
save_flags(flags);
cli();
di = info->isdn_driver;
ch = info->isdn_channel;
di = isdn_slot_driver(info->isdn_slot);
ch = isdn_slot_channel(info->isdn_slot);
__skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
dev->drv[di]->rcvcount[ch] += 2;
restore_flags(flags);
......@@ -685,8 +685,8 @@ isdn_audio_put_dle_code(modem_info * info, u_char code)
ISDN_AUDIO_SKB_LOCK(skb) = 0;
save_flags(flags);
cli();
di = info->isdn_driver;
ch = info->isdn_channel;
di = isdn_slot_driver(info->isdn_slot);
ch = isdn_slot_channel(info->isdn_slot);
__skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
dev->drv[di]->rcvcount[ch] += 2;
restore_flags(flags);
......
......@@ -19,6 +19,7 @@
#include <linux/vmalloc.h>
#include <linux/isdn.h>
#include <linux/smp_lock.h>
#include <linux/ctype.h>
#include "isdn_common.h"
#include "isdn_tty.h"
#include "isdn_net.h"
......@@ -26,24 +27,31 @@
#ifdef CONFIG_ISDN_AUDIO
#include "isdn_audio.h"
#endif
#ifdef CONFIG_ISDN_DIVERSION_MODULE
#define CONFIG_ISDN_DIVERSION
#endif
#ifdef CONFIG_ISDN_DIVERSION
#include <linux/isdn_divertif.h>
#endif /* CONFIG_ISDN_DIVERSION */
#include "isdn_v110.h"
#include <linux/devfs_fs_kernel.h>
/* Debugflags */
#undef ISDN_DEBUG_STATCALLB
MODULE_DESCRIPTION("ISDN4Linux: link layer");
MODULE_AUTHOR("Fritz Elfert");
MODULE_LICENSE("GPL");
isdn_dev *dev;
struct isdn_slot {
int di; /* driver index */
int ch; /* channel index (per driver) */
int usage; /* how is it used */
char num[ISDN_MSNLEN]; /* the current phone number */
unsigned long ibytes; /* Statistics incoming bytes */
unsigned long obytes; /* Statistics outgoing bytes */
struct isdn_v110 iv110; /* For V.110 */
int m_idx; /* Index for mdm.... */
isdn_net_dev *rx_netdev; /* rx netdev-pointers */
isdn_net_dev *st_netdev; /* stat netdev-pointers */
};
static struct isdn_slot slot[ISDN_MAX_CHANNELS];
static char *isdn_revision = "$Revision: 1.114.6.16 $";
extern char *isdn_net_revision;
......@@ -60,15 +68,18 @@ static char *isdn_audio_revision = ": none $";
#endif
extern char *isdn_v110_revision;
#ifdef CONFIG_ISDN_DIVERSION
#if defined(CONFIG_ISDN_DIVERSION) || defined(CONFIG_ISDN_DIVERSION_MODULE)
static isdn_divert_if *divert_if; /* = NULL */
#endif /* CONFIG_ISDN_DIVERSION */
#else
#define divert_if ((isdn_divert_if *) NULL)
#endif
static void set_global_features(void);
static void isdn_register_devfs(int);
static void isdn_unregister_devfs(int);
static int isdn_wildmat(char *s, char *p);
static int isdn_command(isdn_ctrl *cmd);
void
isdn_lock_drivers(void)
......@@ -230,12 +241,11 @@ isdn_dc2minor(int di, int ch)
{
int i;
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
if (dev->chanmap[i] == ch && dev->drvmap[i] == di)
if (slot[i].ch == ch && slot[i].di == di)
return i;
return -1;
}
static int isdn_timer_cnt1 = 0;
static int isdn_timer_cnt2 = 0;
static int isdn_timer_cnt3 = 0;
......@@ -252,11 +262,6 @@ isdn_timer_funct(ulong dummy)
isdn_tty_modem_xmit();
}
if (tf & ISDN_TIMER_SLOW) {
if (++isdn_timer_cnt1 >= ISDN_TIMER_02SEC) {
isdn_timer_cnt1 = 0;
if (tf & ISDN_TIMER_NETDIAL)
isdn_net_dial();
}
if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) {
isdn_timer_cnt2 = 0;
if (tf & ISDN_TIMER_NETHANGUP)
......@@ -291,7 +296,6 @@ isdn_timer_ctrl(int tf, int onoff)
cli();
if ((tf & ISDN_TIMER_SLOW) && (!(dev->tflags & ISDN_TIMER_SLOW))) {
/* If the slow-timer wasn't activated until now */
isdn_timer_cnt1 = 0;
isdn_timer_cnt2 = 0;
}
old_tflags = dev->tflags;
......@@ -317,7 +321,7 @@ isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb)
return;
}
/* Update statistics */
dev->ibytes[i] += skb->len;
slot[i].ibytes += skb->len;
/* First, try to deliver data to network-device */
if (isdn_net_rcv_skb(i, skb))
......@@ -327,10 +331,10 @@ isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb)
* makes sense for async streams only, so it is
* called after possible net-device delivery.
*/
if (dev->v110[i]) {
atomic_inc(&dev->v110use[i]);
skb = isdn_v110_decode(dev->v110[i], skb);
atomic_dec(&dev->v110use[i]);
if (slot[i].iv110.v110) {
atomic_inc(&slot[i].iv110.v110use);
skb = isdn_v110_decode(slot[i].iv110.v110, skb);
atomic_dec(&slot[i].iv110.v110use);
if (!skb)
return;
}
......@@ -350,15 +354,16 @@ isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb)
* lowlevel-driver, use driver's transparent mode and handle V.110 in
* linklevel instead.
*/
int
static int
isdn_command(isdn_ctrl *cmd)
{
int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255);
if (cmd->driver == -1) {
printk(KERN_WARNING "isdn_command command(%x) driver -1\n", cmd->command);
return(1);
}
if (cmd->command == ISDN_CMD_SETL2) {
int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255);
unsigned long l2prot = (cmd->arg >> 8) & 255;
unsigned long features = (dev->drv[cmd->driver]->interface->features
>> ISDN_FEATURE_L2_SHIFT) &
......@@ -374,30 +379,38 @@ isdn_command(isdn_ctrl *cmd)
* Layer-2 to transparent
*/
if (!(features & l2_feature)) {
dev->v110emu[idx] = l2prot;
slot[idx].iv110.v110emu = l2prot;
cmd->arg = (cmd->arg & 255) |
(ISDN_PROTO_L2_TRANS << 8);
} else
dev->v110emu[idx] = 0;
}
slot[idx].iv110.v110emu = 0;
}
}
#ifdef ISDN_DEBUG_COMMAND
switch (cmd->command) {
case ISDN_CMD_SETL2:
printk(KERN_DEBUG "ISDN_CMD_SETL2 %d\n", idx); break;
case ISDN_CMD_SETL3:
printk(KERN_DEBUG "ISDN_CMD_SETL3 %d\n", idx); break;
case ISDN_CMD_DIAL:
printk(KERN_DEBUG "ISDN_CMD_DIAL %d\n", idx); break;
case ISDN_CMD_ACCEPTD:
printk(KERN_DEBUG "ISDN_CMD_ACCEPTD %d\n", idx); break;
case ISDN_CMD_ACCEPTB:
printk(KERN_DEBUG "ISDN_CMD_ACCEPTB %d\n", idx); break;
case ISDN_CMD_HANGUP:
printk(KERN_DEBUG "ISDN_CMD_HANGUP %d\n", idx); break;
case ISDN_CMD_CLREAZ:
printk(KERN_DEBUG "ISDN_CMD_CLREAZ %d\n", idx); break;
case ISDN_CMD_SETEAZ:
printk(KERN_DEBUG "ISDN_CMD_SETEAZ %d\n", idx); break;
default:
printk(KERN_DEBUG "%s: cmd = %d\n", __FUNCTION__, cmd->command);
}
#endif
return dev->drv[cmd->driver]->interface->command(cmd);
}
void
isdn_all_eaz(int di, int ch)
{
isdn_ctrl cmd;
if (di < 0)
return;
cmd.driver = di;
cmd.arg = ch;
cmd.command = ISDN_CMD_SETEAZ;
cmd.parm.num[0] = '\0';
isdn_command(&cmd);
}
/*
* Begin of a CAPI like LL<->HL interface, currently used only for
* supplementary service (CAPI 2.0 part III)
......@@ -430,7 +443,7 @@ isdn_status_callback(isdn_ctrl * c)
int r;
int retval = 0;
isdn_ctrl cmd;
isdn_net_dev *p;
struct list_head *l;
di = c->driver;
i = isdn_dc2minor(di, c->arg);
......@@ -442,7 +455,7 @@ isdn_status_callback(isdn_ctrl * c)
return 0;
if (isdn_net_stat_callback(i, c))
return 0;
if (isdn_v110_stat_callback(i, c))
if (isdn_v110_stat_callback(&slot[i].iv110, c))
return 0;
if (isdn_tty_stat_callback(i, c))
return 0;
......@@ -458,8 +471,8 @@ isdn_status_callback(isdn_ctrl * c)
case ISDN_STAT_RUN:
dev->drv[di]->flags |= DRV_FLAG_RUNNING;
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
if (dev->drvmap[i] == di)
isdn_all_eaz(di, dev->chanmap[i]);
if (slot[i].di == di)
isdn_slot_all_eaz(i);
set_global_features();
break;
case ISDN_STAT_STOP:
......@@ -468,9 +481,7 @@ isdn_status_callback(isdn_ctrl * c)
case ISDN_STAT_ICALL:
if (i < 0)
return -1;
#ifdef ISDN_DEBUG_STATCALLB
printk(KERN_DEBUG "ICALL (net): %d %ld %s\n", di, c->arg, c->parm.num);
#endif
dbg_statcallb("ICALL: %d (%d,%ld) %s\n", i, di, c->arg, c->parm.num);
if (dev->global_flags & ISDN_GLOBAL_STOPPED) {
cmd.driver = di;
cmd.arg = c->arg;
......@@ -489,11 +500,9 @@ isdn_status_callback(isdn_ctrl * c)
*/
if (c->command == ISDN_STAT_ICALL)
if ((retval = isdn_tty_find_icall(di, c->arg, &c->parm.setup))) return(retval);
#ifdef CONFIG_ISDN_DIVERSION
if (divert_if)
if ((retval = divert_if->stat_callback(c)))
return(retval); /* processed */
#endif /* CONFIG_ISDN_DIVERSION */
if ((!retval) && (dev->drv[di]->flags & DRV_FLAG_REJBUS)) {
/* No tty responding */
cmd.driver = di;
......@@ -504,19 +513,15 @@ isdn_status_callback(isdn_ctrl * c)
}
break;
case 1:
/* Schedule connection-setup */
isdn_net_dial();
cmd.driver = di;
cmd.arg = c->arg;
cmd.command = ISDN_CMD_ACCEPTD;
for ( p = dev->netdev; p; p = p->next )
if ( p->local->isdn_channel == cmd.arg )
{
strcpy( cmd.parm.setup.eazmsn, p->local->msn );
isdn_command(&cmd);
list_for_each(l, &isdn_net_devs) {
isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
if (p->local.isdn_slot == i) {
strcpy(cmd.parm.setup.eazmsn, p->local.msn);
isdn_slot_command(i, ISDN_CMD_ACCEPTD, &cmd);
retval = 1;
break;
}
}
break;
case 2: /* For calling back, first reject incoming call ... */
......@@ -532,24 +537,19 @@ isdn_status_callback(isdn_ctrl * c)
/* Fall through */
case 4:
/* ... then start callback. */
isdn_net_dial();
break;
case 5:
/* Number would eventually match, if longer */
retval = 3;
break;
}
#ifdef ISDN_DEBUG_STATCALLB
printk(KERN_DEBUG "ICALL: ret=%d\n", retval);
#endif
dbg_statcallb("ICALL: ret=%d\n", retval);
return retval;
break;
case ISDN_STAT_CINF:
if (i < 0)
return -1;
#ifdef ISDN_DEBUG_STATCALLB
printk(KERN_DEBUG "CINF: %ld %s\n", c->arg, c->parm.num);
#endif
dbg_statcallb("CINF: %d %s\n", i, c->parm.num);
if (dev->global_flags & ISDN_GLOBAL_STOPPED)
return 0;
if (strcmp(c->parm.num, "0"))
......@@ -557,39 +557,29 @@ isdn_status_callback(isdn_ctrl * c)
isdn_tty_stat_callback(i, c);
break;
case ISDN_STAT_CAUSE:
#ifdef ISDN_DEBUG_STATCALLB
printk(KERN_DEBUG "CAUSE: %ld %s\n", c->arg, c->parm.num);
#endif
dbg_statcallb("CAUSE: %d %s\n", i, c->parm.num);
printk(KERN_INFO "isdn: %s,ch%ld cause: %s\n",
dev->drvid[di], c->arg, c->parm.num);
isdn_tty_stat_callback(i, c);
#ifdef CONFIG_ISDN_DIVERSION
if (divert_if)
divert_if->stat_callback(c);
#endif /* CONFIG_ISDN_DIVERSION */
break;
case ISDN_STAT_DISPLAY:
#ifdef ISDN_DEBUG_STATCALLB
printk(KERN_DEBUG "DISPLAY: %ld %s\n", c->arg, c->parm.display);
#endif
dbg_statcallb("DISPLAY: %d %s\n", i, c->parm.display);
isdn_tty_stat_callback(i, c);
#ifdef CONFIG_ISDN_DIVERSION
if (divert_if)
divert_if->stat_callback(c);
#endif /* CONFIG_ISDN_DIVERSION */
break;
case ISDN_STAT_DCONN:
if (i < 0)
return -1;
#ifdef ISDN_DEBUG_STATCALLB
printk(KERN_DEBUG "DCONN: %ld\n", c->arg);
#endif
dbg_statcallb("DCONN: %d\n", i);
if (dev->global_flags & ISDN_GLOBAL_STOPPED)
return 0;
/* Find any net-device, waiting for D-channel setup */
if (isdn_net_stat_callback(i, c))
break;
isdn_v110_stat_callback(i, c);
isdn_v110_stat_callback(&slot[i].iv110, c);
/* Find any ttyI, waiting for D-channel setup */
if (isdn_tty_stat_callback(i, c)) {
cmd.driver = di;
......@@ -602,9 +592,7 @@ isdn_status_callback(isdn_ctrl * c)
case ISDN_STAT_DHUP:
if (i < 0)
return -1;
#ifdef ISDN_DEBUG_STATCALLB
printk(KERN_DEBUG "DHUP: %ld\n", c->arg);
#endif
dbg_statcallb("DHUP: %d\n", i);
if (dev->global_flags & ISDN_GLOBAL_STOPPED)
return 0;
dev->drv[di]->online &= ~(1 << (c->arg));
......@@ -612,21 +600,16 @@ isdn_status_callback(isdn_ctrl * c)
/* Signal hangup to network-devices */
if (isdn_net_stat_callback(i, c))
break;
isdn_v110_stat_callback(i, c);
isdn_v110_stat_callback(&slot[i].iv110, c);
if (isdn_tty_stat_callback(i, c))
break;
#ifdef CONFIG_ISDN_DIVERSION
if (divert_if)
divert_if->stat_callback(c);
#endif /* CONFIG_ISDN_DIVERSION */
break;
break;
case ISDN_STAT_BCONN:
if (i < 0)
return -1;
#ifdef ISDN_DEBUG_STATCALLB
printk(KERN_DEBUG "BCONN: %ld\n", c->arg);
#endif
dbg_statcallb("BCONN: %ld\n", c->arg);
/* Signal B-channel-connect to network-devices */
if (dev->global_flags & ISDN_GLOBAL_STOPPED)
return 0;
......@@ -634,16 +617,14 @@ isdn_status_callback(isdn_ctrl * c)
isdn_info_update();
if (isdn_net_stat_callback(i, c))
break;
isdn_v110_stat_callback(i, c);
isdn_v110_stat_callback(&slot[i].iv110, c);
if (isdn_tty_stat_callback(i, c))
break;
break;
case ISDN_STAT_BHUP:
if (i < 0)
return -1;
#ifdef ISDN_DEBUG_STATCALLB
printk(KERN_DEBUG "BHUP: %ld\n", c->arg);
#endif
dbg_statcallb("BHUP: %d\n", i);
if (dev->global_flags & ISDN_GLOBAL_STOPPED)
return 0;
dev->drv[di]->online &= ~(1 << (c->arg));
......@@ -653,16 +634,14 @@ isdn_status_callback(isdn_ctrl * c)
if (isdn_net_stat_callback(i, c))
break;
#endif
isdn_v110_stat_callback(i, c);
isdn_v110_stat_callback(&slot[i].iv110, c);
if (isdn_tty_stat_callback(i, c))
break;
break;
case ISDN_STAT_NODCH:
if (i < 0)
return -1;
#ifdef ISDN_DEBUG_STATCALLB
printk(KERN_DEBUG "NODCH: %ld\n", c->arg);
#endif
dbg_statcallb("NODCH: %ld\n", c->arg);
if (dev->global_flags & ISDN_GLOBAL_STOPPED)
return 0;
if (isdn_net_stat_callback(i, c))
......@@ -679,20 +658,17 @@ isdn_status_callback(isdn_ctrl * c)
save_flags(flags);
cli();
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
if ((dev->drvmap[i] == di) &&
(dev->chanmap[i] == c->arg)) {
if ((slot[i].di == di) &&
(slot[i].ch == c->arg)) {
if (c->parm.num[0])
dev->usage[i] &= ~ISDN_USAGE_DISABLED;
else
if (USG_NONE(dev->usage[i])) {
dev->usage[i] |= ISDN_USAGE_DISABLED;
}
isdn_slot_set_usage(i, isdn_slot_usage(i) & ~ISDN_USAGE_DISABLED);
else if (USG_NONE(isdn_slot_usage(i)))
isdn_slot_set_usage(i, isdn_slot_usage(i) | ISDN_USAGE_DISABLED);
else
retval = -1;
break;
}
restore_flags(flags);
isdn_info_update();
break;
case ISDN_STAT_UNLOAD:
while (dev->drv[di]->locks > 0) {
......@@ -707,10 +683,10 @@ isdn_status_callback(isdn_ctrl * c)
cli();
isdn_tty_stat_callback(i, c);
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
if (dev->drvmap[i] == di) {
dev->drvmap[i] = -1;
dev->chanmap[i] = -1;
dev->usage[i] &= ~ISDN_USAGE_DISABLED;
if (slot[i].di == di) {
slot[i].di = -1;
slot[i].ch = -1;
slot[i].usage &= ~ISDN_USAGE_DISABLED;
isdn_unregister_devfs(i);
}
dev->drivers--;
......@@ -742,12 +718,10 @@ isdn_status_callback(isdn_ctrl * c)
isdn_tty_stat_callback(i, c);
break;
#endif
#ifdef CONFIG_ISDN_DIVERSION
case ISDN_STAT_PROT:
case ISDN_STAT_REDIR:
if (divert_if)
return(divert_if->stat_callback(c));
#endif /* CONFIG_ISDN_DIVERSION */
default:
return -1;
}
......@@ -770,50 +744,40 @@ isdn_getnum(char **p)
#define DLE 0x10
/*
* isdn_readbchan() tries to get data from the read-queue.
* isdn_slot_readbchan() tries to get data from the read-queue.
* It MUST be called with interrupts off.
*
* Be aware that this is not an atomic operation when sleep != 0, even though
* interrupts are turned off! Well, like that we are currently only called
* on behalf of a read system call on raw device files (which are documented
* to be dangerous and for for debugging purpose only). The inode semaphore
* takes care that this is not called for the same minor device number while
* we are sleeping, but access is not serialized against simultaneous read()
* from the corresponding ttyI device. Can other ugly events, like changes
* of the mapping (di,ch)<->minor, happen during the sleep? --he
*/
int
isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_queue_head_t *sleep)
isdn_slot_readbchan(int sl, u_char * buf, u_char * fp, int len)
{
int count;
int count_pull;
int count_put;
int dflag;
int di = isdn_slot_driver(sl);
int ch = isdn_slot_channel(sl);
struct sk_buff *skb;
u_char *cp;
if (!dev->drv[di])
return 0;
if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) {
if (sleep)
interruptible_sleep_on(sleep);
else
if (skb_queue_empty(&dev->drv[di]->rpqueue[ch]))
return 0;
}
if (len > dev->drv[di]->rcvcount[channel])
len = dev->drv[di]->rcvcount[channel];
if (len > dev->drv[di]->rcvcount[ch])
len = dev->drv[di]->rcvcount[ch];
cp = buf;
count = 0;
while (len) {
if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel])))
if (!(skb = skb_peek(&dev->drv[di]->rpqueue[ch])))
break;
#ifdef CONFIG_ISDN_AUDIO
if (ISDN_AUDIO_SKB_LOCK(skb))
break;
ISDN_AUDIO_SKB_LOCK(skb) = 1;
if ((ISDN_AUDIO_SKB_DLECOUNT(skb)) || (dev->drv[di]->DLEflag & (1 << channel))) {
if ((ISDN_AUDIO_SKB_DLECOUNT(skb)) || (dev->drv[di]->DLEflag & (1 << ch))) {
char *p = skb->data;
unsigned long DLEmask = (1 << channel);
unsigned long DLEmask = (1 << ch);
dflag = 0;
count_pull = count_put = 0;
......@@ -864,7 +828,7 @@ isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_que
#ifdef CONFIG_ISDN_AUDIO
ISDN_AUDIO_SKB_LOCK(skb) = 0;
#endif
skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
skb = skb_dequeue(&dev->drv[di]->rpqueue[ch]);
dev_kfree_skb(skb);
} else {
/* Not yet emptied this buff, so it
......@@ -876,7 +840,7 @@ isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_que
ISDN_AUDIO_SKB_LOCK(skb) = 0;
#endif
}
dev->drv[di]->rcvcount[channel] -= count_put;
dev->drv[di]->rcvcount[ch] -= count_put;
}
return count;
}
......@@ -884,13 +848,13 @@ isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_que
static __inline int
isdn_minor2drv(int minor)
{
return (dev->drvmap[minor]);
return slot[minor].di;
}
static __inline int
isdn_minor2chan(int minor)
{
return (dev->chanmap[minor]);
return slot[minor].ch;
}
static char *
......@@ -903,25 +867,25 @@ isdn_statstr(void)
sprintf(istatbuf, "idmap:\t");
p = istatbuf + strlen(istatbuf);
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
sprintf(p, "%s ", (dev->drvmap[i] < 0) ? "-" : dev->drvid[dev->drvmap[i]]);
sprintf(p, "%s ", (slot[i].di < 0) ? "-" : dev->drvid[slot[i].di]);
p = istatbuf + strlen(istatbuf);
}
sprintf(p, "\nchmap:\t");
p = istatbuf + strlen(istatbuf);
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
sprintf(p, "%d ", dev->chanmap[i]);
sprintf(p, "%d ", slot[i].ch);
p = istatbuf + strlen(istatbuf);
}
sprintf(p, "\ndrmap:\t");
p = istatbuf + strlen(istatbuf);
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
sprintf(p, "%d ", dev->drvmap[i]);
sprintf(p, "%d ", slot[i].di);
p = istatbuf + strlen(istatbuf);
}
sprintf(p, "\nusage:\t");
p = istatbuf + strlen(istatbuf);
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
sprintf(p, "%d ", dev->usage[i]);
sprintf(p, "%d ", slot[i].usage);
p = istatbuf + strlen(istatbuf);
}
sprintf(p, "\nflags:\t");
......@@ -938,7 +902,7 @@ isdn_statstr(void)
sprintf(p, "\nphone:\t");
p = istatbuf + strlen(istatbuf);
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
sprintf(p, "%s ", dev->num[i]);
sprintf(p, "%s ", isdn_slot_num(i));
p = istatbuf + strlen(istatbuf);
}
sprintf(p, "\n");
......@@ -1095,8 +1059,8 @@ isdn_status_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
sizeof(ulong) * ISDN_MAX_CHANNELS * 2)))
return ret;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
put_user(dev->ibytes[i], p++);
put_user(dev->obytes[i], p++);
put_user(slot[i].ibytes, p++);
put_user(slot[i].obytes, p++);
}
return 0;
} else
......@@ -1279,10 +1243,9 @@ isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
int ret;
int i;
char *p;
char *s;
union iocpar {
char name[10];
char bname[22];
char bname[20];
isdn_ioctl_struct iocts;
isdn_net_ioctl_phone phone;
isdn_net_ioctl_cfg cfg;
......@@ -1310,42 +1273,24 @@ isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
#ifdef CONFIG_NETDEVICES
case IIOCNETAIF:
/* Add a network-interface */
if (arg) {
if (copy_from_user(name, (char *) arg, sizeof(name)))
if (copy_from_user(name, (char *) arg, sizeof(name) - 1))
return -EFAULT;
s = name;
} else {
s = NULL;
}
name[sizeof(name)-1] = 0;
ret = down_interruptible(&dev->sem);
if( ret ) return ret;
if ((s = isdn_net_new(s, NULL))) {
if (copy_to_user((char *) arg, s, strlen(s) + 1)){
ret = -EFAULT;
} else {
ret = 0;
}
} else
ret = -ENODEV;
if (ret)
return ret;
ret = isdn_net_new(name, NULL);
up(&dev->sem);
return ret;
case IIOCNETASL:
/* Add a slave to a network-interface */
if (arg) {
if (copy_from_user(bname, (char *) arg, sizeof(bname) - 1))
return -EFAULT;
} else
return -EINVAL;
bname[sizeof(bname)-1] = 0;
ret = down_interruptible(&dev->sem);
if( ret ) return ret;
if ((s = isdn_net_newslave(bname))) {
if (copy_to_user((char *) arg, s, strlen(s) + 1)){
ret = -EFAULT;
} else {
ret = 0;
}
} else
ret = -ENODEV;
if (ret)
return ret;
ret = isdn_net_newslave(bname);
up(&dev->sem);
return ret;
case IIOCNETDIF:
......@@ -1742,8 +1687,8 @@ isdn_map_eaz2msn(char *msn, int di)
#define L2V (~(ISDN_FEATURE_L2_V11096|ISDN_FEATURE_L2_V11019|ISDN_FEATURE_L2_V11038))
int
isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
,int pre_chan, char *msn)
isdn_get_free_slot(int usage, int l2_proto, int l3_proto,
int pre_dev, int pre_chan, char *msn)
{
int i;
ulong flags;
......@@ -1760,38 +1705,32 @@ isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
* because we can emulate this in linklevel.
*/
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
if (USG_NONE(dev->usage[i]) &&
(dev->drvmap[i] != -1)) {
int d = dev->drvmap[i];
if ((dev->usage[i] & ISDN_USAGE_EXCLUSIVE) &&
((pre_dev != d) || (pre_chan != dev->chanmap[i])))
if (USG_NONE(slot[i].usage) &&
(slot[i].di != -1)) {
int d = slot[i].di;
if ((slot[i].usage & ISDN_USAGE_EXCLUSIVE) &&
((pre_dev != d) || (pre_chan != slot[i].ch)))
continue;
if (!strcmp(isdn_map_eaz2msn(msn, d), "-"))
continue;
if (dev->usage[i] & ISDN_USAGE_DISABLED)
if (slot[i].usage & ISDN_USAGE_DISABLED)
continue; /* usage not allowed */
if (dev->drv[d]->flags & DRV_FLAG_RUNNING) {
if (((dev->drv[d]->interface->features & features) == features) ||
(((dev->drv[d]->interface->features & vfeatures) == vfeatures) &&
(dev->drv[d]->interface->features & ISDN_FEATURE_L2_TRANS))) {
if ((pre_dev < 0) || (pre_chan < 0)) {
dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
dev->usage[i] |= usage;
isdn_info_update();
isdn_slot_set_usage(i, (isdn_slot_usage(i) & ISDN_USAGE_EXCLUSIVE) | usage);
restore_flags(flags);
return i;
} else {
if ((pre_dev == d) && (pre_chan == dev->chanmap[i])) {
dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
dev->usage[i] |= usage;
isdn_info_update();
} else if ((pre_dev == d) && (pre_chan == slot[i].ch)) {
isdn_slot_set_usage(i, (isdn_slot_usage(i) & ISDN_USAGE_EXCLUSIVE) | usage);
restore_flags(flags);
return i;
}
}
}
}
}
restore_flags(flags);
return -1;
}
......@@ -1802,27 +1741,31 @@ isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
void
isdn_free_channel(int di, int ch, int usage)
{
int i;
ulong flags;
int sl;
sl = isdn_dc2minor(di, ch);
isdn_slot_free(sl, usage);
}
void
isdn_slot_free(int sl, int usage)
{
unsigned long flags;
save_flags(flags);
cli();
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
if (((!usage) || ((dev->usage[i] & ISDN_USAGE_MASK) == usage)) &&
(dev->drvmap[i] == di) &&
(dev->chanmap[i] == ch)) {
dev->usage[i] &= (ISDN_USAGE_NONE | ISDN_USAGE_EXCLUSIVE);
strcpy(dev->num[i], "???");
dev->ibytes[i] = 0;
dev->obytes[i] = 0;
if (!usage || (slot[sl].usage & ISDN_USAGE_MASK) == usage) {
strcpy(isdn_slot_num(sl), "???");
slot[sl].ibytes = 0;
slot[sl].obytes = 0;
// 20.10.99 JIM, try to reinitialize v110 !
dev->v110emu[i] = 0;
atomic_set(&(dev->v110use[i]), 0);
isdn_v110_close(dev->v110[i]);
dev->v110[i] = NULL;
slot[sl].iv110.v110emu = 0;
atomic_set(&slot[sl].iv110.v110use, 0);
isdn_v110_close(slot[sl].iv110.v110);
slot[sl].iv110.v110 = NULL;
// 20.10.99 JIM, try to reinitialize v110 !
isdn_info_update();
skb_queue_purge(&dev->drv[di]->rpqueue[ch]);
isdn_slot_set_usage(sl, isdn_slot_usage(sl) & (ISDN_USAGE_NONE | ISDN_USAGE_EXCLUSIVE));
skb_queue_purge(&dev->drv[isdn_slot_driver(sl)]->rpqueue[isdn_slot_channel(sl)]);
}
restore_flags(flags);
}
......@@ -1839,10 +1782,9 @@ isdn_unexclusive_channel(int di, int ch)
save_flags(flags);
cli();
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
if ((dev->drvmap[i] == di) &&
(dev->chanmap[i] == ch)) {
dev->usage[i] &= ~ISDN_USAGE_EXCLUSIVE;
isdn_info_update();
if ((slot[i].di == di) &&
(slot[i].ch == ch)) {
isdn_slot_set_usage(i, isdn_slot_usage(i) & ~ISDN_USAGE_EXCLUSIVE);
restore_flags(flags);
return;
}
......@@ -1853,17 +1795,20 @@ isdn_unexclusive_channel(int di, int ch)
* Return: length of data on success, -ERRcode on failure.
*/
int
isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb)
isdn_slot_write(int sl, struct sk_buff *skb)
{
int ret;
struct sk_buff *nskb = NULL;
int v110_ret = skb->len;
int idx = isdn_dc2minor(drvidx, chan);
int di = isdn_slot_driver(sl);
int ch = isdn_slot_channel(sl);
if (dev->v110[idx]) {
atomic_inc(&dev->v110use[idx]);
nskb = isdn_v110_encode(dev->v110[idx], skb);
atomic_dec(&dev->v110use[idx]);
BUG_ON(sl < 0);
if (slot[sl].iv110.v110) {
atomic_inc(&slot[sl].iv110.v110use);
nskb = isdn_v110_encode(slot[sl].iv110.v110, skb);
atomic_dec(&slot[sl].iv110.v110use);
if (!nskb)
return 0;
v110_ret = *((int *)nskb->data);
......@@ -1873,10 +1818,9 @@ isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb)
return v110_ret;
}
/* V.110 must always be acknowledged */
ack = 1;
ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, nskb);
ret = dev->drv[di]->interface->writebuf_skb(di, ch, 1, nskb);
} else {
int hl = dev->drv[drvidx]->interface->hl_hdrlen;
int hl = isdn_slot_hdrlen(sl);
if( skb_headroom(skb) < hl ){
/*
......@@ -1892,22 +1836,22 @@ isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb)
skb_tmp = skb_realloc_headroom(skb, hl);
printk(KERN_DEBUG "isdn_writebuf_skb_stub: reallocating headroom%s\n", skb_tmp ? "" : " failed");
if (!skb_tmp) return -ENOMEM; /* 0 better? */
ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb_tmp);
ret = dev->drv[di]->interface->writebuf_skb(di, ch, 1, skb_tmp);
if( ret > 0 ){
dev_kfree_skb(skb);
} else {
dev_kfree_skb(skb_tmp);
}
} else {
ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb);
ret = dev->drv[di]->interface->writebuf_skb(di, ch, 1, skb);
}
}
if (ret > 0) {
dev->obytes[idx] += ret;
if (dev->v110[idx]) {
atomic_inc(&dev->v110use[idx]);
dev->v110[idx]->skbuser++;
atomic_dec(&dev->v110use[idx]);
slot[sl].obytes += ret;
if (slot[sl].iv110.v110) {
atomic_inc(&slot[sl].iv110.v110use);
slot[sl].iv110.v110->skbuser++;
atomic_dec(&slot[sl].iv110.v110use);
/* For V.110 return unencoded data length */
ret = v110_ret;
/* if the complete frame was send we free the skb;
......@@ -1916,7 +1860,7 @@ isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb)
dev_kfree_skb(skb);
}
} else
if (dev->v110[idx])
if (slot[sl].iv110.v110)
dev_kfree_skb(nskb);
return ret;
}
......@@ -1997,9 +1941,9 @@ isdn_add_channels(driver *d, int drvidx, int n, int adding)
cli();
for (j = d->channels; j < m; j++)
for (k = 0; k < ISDN_MAX_CHANNELS; k++)
if (dev->chanmap[k] < 0) {
dev->chanmap[k] = j;
dev->drvmap[k] = drvidx;
if (slot[k].ch < 0) {
slot[k].ch = j;
slot[k].di = drvidx;
isdn_register_devfs(k);
break;
}
......@@ -2026,7 +1970,7 @@ set_global_features(void)
}
}
#ifdef CONFIG_ISDN_DIVERSION
#if defined(CONFIG_ISDN_DIVERSION) || defined(CONFIG_ISDN_DIVERSION_MODULE)
static char *map_drvname(int di)
{
......@@ -2075,7 +2019,7 @@ int DIVERT_REG_NAME(isdn_divert_if *i_div)
EXPORT_SYMBOL(DIVERT_REG_NAME);
#endif /* CONFIG_ISDN_DIVERSION */
#endif
EXPORT_SYMBOL(register_isdn);
......@@ -2140,6 +2084,186 @@ register_isdn(isdn_if * i)
return 1;
}
int
isdn_slot_driver(int sl)
{
BUG_ON(sl < 0);
return slot[sl].di;
}
int
isdn_slot_channel(int sl)
{
BUG_ON(sl < 0);
return slot[sl].ch;
}
int
isdn_slot_hdrlen(int sl)
{
int di = isdn_slot_driver(sl);
return dev->drv[di]->interface->hl_hdrlen;
}
char *
isdn_slot_map_eaz2msn(int sl, char *msn)
{
int di = isdn_slot_driver(sl);
return isdn_map_eaz2msn(msn, di);
}
int
isdn_slot_command(int sl, int cmd, isdn_ctrl *ctrl)
{
ctrl->command = cmd;
ctrl->driver = isdn_slot_driver(sl);
switch (cmd) {
case ISDN_CMD_SETL2:
case ISDN_CMD_SETL3:
case ISDN_CMD_PROT_IO:
ctrl->arg &= ~0xff; ctrl->arg |= isdn_slot_channel(sl);
break;
default:
ctrl->arg = isdn_slot_channel(sl);
break;
}
return isdn_command(ctrl);
}
int
isdn_slot_dial(int sl, struct dial_info *dial)
{
isdn_ctrl cmd;
int retval;
char *msn = isdn_slot_map_eaz2msn(sl, dial->msn);
/* check for DOV */
if (dial->si1 == 7 && tolower(dial->phone[0]) == 'v') { /* DOV call */
dial->si1 = 1;
dial->phone++; /* skip v/V */
}
strcpy(isdn_slot_num(sl), dial->phone);
isdn_slot_set_usage(sl, isdn_slot_usage(sl) | ISDN_USAGE_OUTGOING);
retval = isdn_slot_command(sl, ISDN_CMD_CLREAZ, &cmd);
if (retval)
return retval;
strcpy(cmd.parm.num, msn);
retval = isdn_slot_command(sl, ISDN_CMD_SETEAZ, &cmd);
cmd.arg = dial->l2_proto << 8;
cmd.parm.fax = dial->fax;
retval = isdn_slot_command(sl, ISDN_CMD_SETL2, &cmd);
if (retval)
return retval;
cmd.arg = dial->l3_proto << 8;
retval = isdn_slot_command(sl, ISDN_CMD_SETL3, &cmd);
if (retval)
return retval;
cmd.parm.setup.si1 = dial->si1;
cmd.parm.setup.si2 = dial->si2;
strcpy(cmd.parm.setup.eazmsn, msn);
strcpy(cmd.parm.setup.phone, dial->phone);
printk(KERN_INFO "ISDN: slot %d: Dialing %s -> %s (SI %d/%d) (B %d/%d)\n",
sl, cmd.parm.setup.eazmsn, cmd.parm.setup.phone,
cmd.parm.setup.si1, cmd.parm.setup.si2,
dial->l2_proto, dial->l3_proto);
return isdn_slot_command(sl, ISDN_CMD_DIAL, &cmd);
}
void
isdn_slot_all_eaz(int sl)
{
isdn_ctrl cmd;
cmd.parm.num[0] = '\0';
isdn_slot_command(sl, ISDN_CMD_SETEAZ, &cmd);
}
int
isdn_slot_usage(int sl)
{
BUG_ON(sl < 0);
return slot[sl].usage;
}
void
isdn_slot_set_usage(int sl, int usage)
{
BUG_ON(sl < 0);
slot[sl].usage = usage;
isdn_info_update();
}
int
isdn_slot_m_idx(int sl)
{
BUG_ON(sl < 0);
return slot[sl].m_idx;
}
void
isdn_slot_set_m_idx(int sl, int midx)
{
BUG_ON(sl < 0);
slot[sl].m_idx = midx;
}
char *
isdn_slot_num(int sl)
{
BUG_ON(sl < 0);
return slot[sl].num;
}
void
isdn_slot_set_rx_netdev(int sl, isdn_net_dev *nd)
{
BUG_ON(sl < 0);
slot[sl].rx_netdev = nd;
}
isdn_net_dev *
isdn_slot_rx_netdev(int sl)
{
BUG_ON(sl < 0);
return slot[sl].rx_netdev;
}
void
isdn_slot_set_st_netdev(int sl, isdn_net_dev *nd)
{
BUG_ON(sl < 0);
slot[sl].st_netdev = nd;
}
isdn_net_dev *
isdn_slot_st_netdev(int sl)
{
BUG_ON(sl < 0);
return slot[sl].st_netdev;
}
/*
*****************************************************************************
* And now the modules code.
......@@ -2247,53 +2371,43 @@ static void isdn_cleanup_devfs(void)
static int __init isdn_init(void)
{
int i;
int retval;
char tmprev[50];
if (!(dev = (isdn_dev *) vmalloc(sizeof(isdn_dev)))) {
printk(KERN_WARNING "isdn: Could not allocate device-struct.\n");
return -EIO;
dev = vmalloc(sizeof(*dev));
if (!dev) {
retval = -ENOMEM;
goto err;
}
memset((char *) dev, 0, sizeof(isdn_dev));
memset(dev, 0, sizeof(*dev));
init_timer(&dev->timer);
dev->timer.function = isdn_timer_funct;
init_MUTEX(&dev->sem);
init_waitqueue_head(&dev->info_waitq);
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
dev->drvmap[i] = -1;
dev->chanmap[i] = -1;
dev->m_idx[i] = -1;
strcpy(dev->num[i], "???");
slot[i].di = -1;
slot[i].ch = -1;
slot[i].m_idx = -1;
strcpy(isdn_slot_num(i), "???");
init_waitqueue_head(&dev->mdm.info[i].open_wait);
init_waitqueue_head(&dev->mdm.info[i].close_wait);
}
if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
retval = register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops);
if (retval) {
printk(KERN_WARNING "isdn: Could not register control devices\n");
vfree(dev);
return -EIO;
goto err_vfree;
}
isdn_init_devfs();
if ((i = isdn_tty_modem_init()) < 0) {
retval = isdn_tty_init();
if (retval < 0) {
printk(KERN_WARNING "isdn: Could not register tty devices\n");
if (i == -3)
tty_unregister_driver(&dev->mdm.cua_modem);
if (i <= -2)
tty_unregister_driver(&dev->mdm.tty_modem);
vfree(dev);
isdn_cleanup_devfs();
unregister_chrdev(ISDN_MAJOR, "isdn");
return -EIO;
goto err_cleanup_devfs;
}
#ifdef CONFIG_ISDN_PPP
if (isdn_ppp_init() < 0) {
retval = isdn_ppp_init();
if (retval < 0) {
printk(KERN_WARNING "isdn: Could not create PPP-device-structs\n");
tty_unregister_driver(&dev->mdm.tty_modem);
tty_unregister_driver(&dev->mdm.cua_modem);
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
kfree(dev->mdm.info[i].xmit_buf - 4);
isdn_cleanup_devfs();
unregister_chrdev(ISDN_MAJOR, "isdn");
vfree(dev);
return -EIO;
goto err_tty_modem;
}
#endif /* CONFIG_ISDN_PPP */
......@@ -2317,6 +2431,16 @@ static int __init isdn_init(void)
#endif
isdn_info_update();
return 0;
err_tty_modem:
isdn_tty_exit();
err_cleanup_devfs:
isdn_cleanup_devfs();
unregister_chrdev(ISDN_MAJOR, "isdn");
err_vfree:
vfree(dev);
err:
return retval;
}
/*
......@@ -2325,46 +2449,24 @@ static int __init isdn_init(void)
static void __exit isdn_exit(void)
{
unsigned long flags;
int i;
#ifdef CONFIG_ISDN_PPP
isdn_ppp_cleanup();
#endif
save_flags(flags);
cli();
if (isdn_net_rmall() < 0) {
printk(KERN_WARNING "isdn: net-device busy, remove cancelled\n");
restore_flags(flags);
return;
}
if (tty_unregister_driver(&dev->mdm.tty_modem)) {
printk(KERN_WARNING "isdn: ttyI-device busy, remove cancelled\n");
restore_flags(flags);
return;
}
if (tty_unregister_driver(&dev->mdm.cua_modem)) {
printk(KERN_WARNING "isdn: cui-device busy, remove cancelled\n");
restore_flags(flags);
return;
}
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
isdn_tty_cleanup_xmit(&dev->mdm.info[i]);
kfree(dev->mdm.info[i].xmit_buf - 4);
#ifdef CONFIG_ISDN_TTY_FAX
kfree(dev->mdm.info[i].fax);
#endif
}
if (unregister_chrdev(ISDN_MAJOR, "isdn") != 0) {
printk(KERN_WARNING "isdn: controldevice busy, remove cancelled\n");
restore_flags(flags);
} else {
if (isdn_net_rmall() < 0)
BUG();
isdn_tty_exit();
if (unregister_chrdev(ISDN_MAJOR, "isdn"))
BUG();
isdn_cleanup_devfs();
del_timer(&dev->timer);
restore_flags(flags);
/* call vfree with interrupts enabled, else it will hang */
vfree(dev);
printk(KERN_NOTICE "ISDN-subsystem unloaded\n");
}
}
module_init(isdn_init);
......
......@@ -23,6 +23,32 @@
#undef ISDN_DEBUG_NET_DUMP
#undef ISDN_DEBUG_NET_DIAL
#undef ISDN_DEBUG_NET_ICALL
#undef ISDN_DEBUG_STATCALLB
#undef ISDN_DEBUG_COMMAND
#ifdef ISDN_DEBUG_NET_DIAL
#define dbg_net_dial(arg...) printk(KERN_DEBUG arg)
#else
#define dbg_net_dial(arg...) do {} while (0)
#endif
#ifdef ISDN_DEBUG_NET_ICALL
#define dbg_net_icall(arg...) printk(KERN_DEBUG arg)
#else
#define dbg_net_icall(arg...) do {} while (0)
#endif
#ifdef ISDN_DEBUG_STATCALLB
#define dbg_statcallb(arg...) printk(KERN_DEBUG arg)
#else
#define dbg_statcallb(arg...) do {} while (0)
#endif
#define isdn_BUG() \
do { printk(KERN_WARNING "ISDN Bug at %s:%d\n", __FILE__, __LINE__); \
} while(0)
#define HERE printk("%s:%d (%s)\n", __FILE__, __LINE__, __FUNCTION__)
/* Prototypes */
extern void isdn_MOD_INC_USE_COUNT(void);
......@@ -30,20 +56,50 @@ extern void isdn_MOD_DEC_USE_COUNT(void);
extern void isdn_lock_drivers(void);
extern void isdn_unlock_drivers(void);
extern void isdn_free_channel(int di, int ch, int usage);
extern void isdn_all_eaz(int di, int ch);
extern int isdn_command(isdn_ctrl *);
extern int isdn_dc2minor(int di, int ch);
extern void isdn_info_update(void);
extern char *isdn_map_eaz2msn(char *msn, int di);
extern void isdn_timer_ctrl(int tf, int onoff);
extern void isdn_unexclusive_channel(int di, int ch);
extern int isdn_getnum(char **);
extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *);
extern int isdn_get_free_channel(int, int, int, int, int, char *);
extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
extern int register_isdn(isdn_if * i);
extern int isdn_msncmp( const char *, const char *);
extern int isdn_add_channels(driver *, int, int, int);
#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) { }
#endif
struct dial_info {
int l2_proto;
int l3_proto;
struct T30_s *fax;
unsigned char si1;
unsigned char si2;
unsigned char *msn;
unsigned char *phone;
};
extern struct list_head isdn_net_devs;
extern int isdn_get_free_slot(int, int, int, int, int, char *);
extern void isdn_slot_free(int slot, int usage);
extern void isdn_slot_all_eaz(int slot);
extern int isdn_slot_command(int slot, int cmd, isdn_ctrl *);
extern int isdn_slot_dial(int slot, struct dial_info *dial);
extern char *isdn_slot_map_eaz2msn(int slot, char *msn);
extern int isdn_slot_write(int slot, struct sk_buff *);
extern int isdn_slot_readbchan(int slot, u_char *, u_char *, int);
extern int isdn_slot_hdrlen(int slot);
extern int isdn_slot_driver(int slot);
extern int isdn_slot_channel(int slot);
extern int isdn_slot_usage(int slot);
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_rx_netdev(int sl, isdn_net_dev *nd);
extern void isdn_slot_set_st_netdev(int sl, isdn_net_dev *nd);
extern isdn_net_dev *isdn_slot_rx_netdev(int sl);
extern isdn_net_dev *isdn_slot_st_netdev(int sl);
......@@ -38,6 +38,27 @@
#include "isdn_concap.h"
#endif
enum {
ST_NULL,
ST_OUT_WAIT_DCONN,
ST_OUT_WAIT_BCONN,
ST_IN_WAIT_DCONN,
ST_IN_WAIT_BCONN,
ST_ACTIVE,
ST_WAIT_BEFORE_CB,
};
/* keep clear of ISDN_CMD_* and ISDN_STAT_* */
enum {
EV_NET_DIAL = 0x200,
EV_NET_TIMER_IN_DCONN = 0x201,
EV_NET_TIMER_IN_BCONN = 0x202,
EV_NET_TIMER_OUT_DCONN = 0x203,
EV_NET_TIMER_OUT_BCONN = 0x204,
EV_NET_TIMER_CB = 0x205,
};
LIST_HEAD(isdn_net_devs); /* Linked list of isdn_net_dev's */
/*
* Outline of new tbusy handling:
......@@ -72,7 +93,7 @@
*/
static __inline__ int isdn_net_device_started(isdn_net_dev *n)
{
isdn_net_local *lp = n->local;
isdn_net_local *lp = &n->local;
struct net_device *dev;
if (lp->master)
......@@ -179,10 +200,13 @@ static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp)
int isdn_net_force_dial_lp(isdn_net_local *);
static int isdn_net_start_xmit(struct sk_buff *, struct net_device *);
static int do_dialout(isdn_net_local *lp);
static void isdn_net_ciscohdlck_connected(isdn_net_local *lp);
static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp);
static int isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg);
char *isdn_net_revision = "$Revision: 1.140.6.11 $";
/*
......@@ -280,10 +304,9 @@ isdn_net_bind_channel(isdn_net_local * lp, int idx)
save_flags(flags);
cli();
lp->flags |= ISDN_NET_CONNECTED;
lp->isdn_device = dev->drvmap[idx];
lp->isdn_channel = dev->chanmap[idx];
dev->rx_netdev[idx] = lp->netdev;
dev->st_netdev[idx] = lp->netdev;
lp->isdn_slot = idx;
isdn_slot_set_rx_netdev(lp->isdn_slot, lp->netdev);
isdn_slot_set_st_netdev(lp->isdn_slot, lp->netdev);
restore_flags(flags);
}
......@@ -306,13 +329,14 @@ isdn_net_unbind_channel(isdn_net_local * lp)
*/
qdisc_reset(lp->netdev->dev.qdisc);
}
lp->dialstate = 0;
dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
dev->st_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
isdn_free_channel(lp->isdn_device, lp->isdn_channel, ISDN_USAGE_NET);
lp->dialstate = ST_NULL;
if (lp->isdn_slot >= 0) {
isdn_slot_set_rx_netdev(lp->isdn_slot, NULL);
isdn_slot_set_st_netdev(lp->isdn_slot, NULL);
isdn_slot_free(lp->isdn_slot, ISDN_USAGE_NET);
}
lp->flags &= ~ISDN_NET_CONNECTED;
lp->isdn_device = -1;
lp->isdn_channel = -1;
lp->isdn_slot = -1;
restore_flags(flags);
}
......@@ -335,12 +359,13 @@ unsigned long last_jiffies = -HZ;
void
isdn_net_autohup()
{
isdn_net_dev *p = dev->netdev;
struct list_head *l;
int anymore;
anymore = 0;
while (p) {
isdn_net_local *l = p->local;
list_for_each(l, &isdn_net_devs) {
isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
isdn_net_local *l = &p->local;
if (jiffies == last_jiffies)
l->cps = l->transcount;
else
......@@ -348,9 +373,10 @@ isdn_net_autohup()
l->transcount = 0;
if (dev->net_verbose > 3)
printk(KERN_DEBUG "%s: %d bogocps\n", l->name, l->cps);
if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) {
if ((l->flags & ISDN_NET_CONNECTED) && (l->dialstate == ST_ACTIVE)) {
anymore = 1;
l->huptimer++;
printk("huptimer %d, onhtime %d, chargetime %d, chargeint %d\n", l->huptimer, l->onhtime, l->chargetime, l->chargeint);
/*
* if there is some dialmode where timeout-hangup
* should _not_ be done, check for that here
......@@ -363,8 +389,10 @@ isdn_net_autohup()
while (time_after(jiffies, l->chargetime + l->chargeint))
l->chargetime += l->chargeint;
if (time_after(jiffies, l->chargetime + l->chargeint - 2 * HZ))
if (l->outgoing || l->hupflags & ISDN_INHUP)
if (l->outgoing || l->hupflags & ISDN_INHUP) {
HERE;
isdn_net_hangup(&p->dev);
}
} else if (l->outgoing) {
if (l->hupflags & ISDN_CHARGEHUP) {
if (l->hupflags & ISDN_WAITCHARGE) {
......@@ -378,16 +406,17 @@ isdn_net_autohup()
isdn_net_hangup(&p->dev);
}
}
} else if (l->hupflags & ISDN_INHUP)
} else if (l->hupflags & ISDN_INHUP) {
HERE;
isdn_net_hangup(&p->dev);
}
}
if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_OFF)) {
isdn_net_hangup(&p->dev);
break;
}
}
p = (isdn_net_dev *) p->next;
}
last_jiffies = jiffies;
isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, anymore);
......@@ -398,104 +427,13 @@ static void isdn_net_lp_disconnected(isdn_net_local *lp)
isdn_net_rm_from_bundle(lp);
}
/*
* Handle status-messages from ISDN-interfacecard.
* This function is called from within the main-status-dispatcher
* isdn_status_callback, which itself is called from the low-level driver.
* Return: 1 = Event handled, 0 = not for us or unknown Event.
*/
int
isdn_net_stat_callback(int idx, isdn_ctrl *c)
static void isdn_net_connected(isdn_net_local *lp)
{
isdn_net_dev *p = dev->st_netdev[idx];
int cmd = c->command;
if (p) {
isdn_net_local *lp = p->local;
#ifdef CONFIG_ISDN_X25
struct concap_proto *cprot = lp -> netdev -> cprot;
struct concap_proto_ops *pops = cprot ? cprot -> pops : 0;
#endif
switch (cmd) {
case ISDN_STAT_BSENT:
/* A packet has successfully been sent out */
if ((lp->flags & ISDN_NET_CONNECTED) &&
(!lp->dialstate)) {
isdn_net_dec_frame_cnt(lp);
lp->stats.tx_packets++;
lp->stats.tx_bytes += c->parm.length;
}
return 1;
case ISDN_STAT_DCONN:
/* D-Channel is up */
switch (lp->dialstate) {
case 4:
case 7:
case 8:
lp->dialstate++;
return 1;
case 12:
lp->dialstate = 5;
return 1;
}
break;
case ISDN_STAT_DHUP:
/* Either D-Channel-hangup or error during dialout */
#ifdef CONFIG_ISDN_X25
/* If we are not connencted then dialing had
failed. If there are generic encap protocol
receiver routines signal the closure of
the link*/
if( !(lp->flags & ISDN_NET_CONNECTED)
&& pops && pops -> disconn_ind )
pops -> disconn_ind(cprot);
#endif /* CONFIG_ISDN_X25 */
if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) {
if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
isdn_net_ciscohdlck_disconnected(lp);
#ifdef CONFIG_ISDN_PPP
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
isdn_ppp_free(lp);
#endif
isdn_net_lp_disconnected(lp);
isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
printk(KERN_INFO "%s: remote hangup\n", lp->name);
printk(KERN_INFO "%s: Chargesum is %d\n", lp->name,
lp->charge);
isdn_net_unbind_channel(lp);
return 1;
}
break;
#ifdef CONFIG_ISDN_X25
case ISDN_STAT_BHUP:
/* B-Channel-hangup */
/* try if there are generic encap protocol
receiver routines and signal the closure of
the link */
if( pops && pops -> disconn_ind ){
pops -> disconn_ind(cprot);
return 1;
}
break;
#endif /* CONFIG_ISDN_X25 */
case ISDN_STAT_BCONN:
/* B-Channel is up */
isdn_net_zero_frame_cnt(lp);
switch (lp->dialstate) {
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 12:
if (lp->dialstate <= 6) {
dev->usage[idx] |= ISDN_USAGE_OUTGOING;
isdn_info_update();
} else
dev->rx_netdev[idx] = p;
lp->dialstate = 0;
lp->dialstate = ST_ACTIVE;
isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1);
if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
isdn_net_ciscohdlck_connected(lp);
......@@ -528,168 +466,125 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
/* ppp needs to do negotiations first */
if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
isdn_net_device_wake_queue(lp);
return 1;
}
break;
case ISDN_STAT_NODCH:
/* No D-Channel avail. */
if (lp->dialstate == 4) {
lp->dialstate--;
return 1;
}
break;
case ISDN_STAT_CINF:
/* Charge-info from TelCo. Calculate interval between
* charge-infos and set timestamp for last info for
* usage by isdn_net_autohup()
*/
lp->charge++;
if (lp->hupflags & ISDN_HAVECHARGE) {
lp->hupflags &= ~ISDN_WAITCHARGE;
lp->chargeint = jiffies - lp->chargetime - (2 * HZ);
}
if (lp->hupflags & ISDN_WAITCHARGE)
lp->hupflags |= ISDN_HAVECHARGE;
lp->chargetime = jiffies;
printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %lu\n",
lp->name, lp->chargetime);
return 1;
}
}
return 0;
}
/*
* Perform dialout for net-interfaces and timeout-handling for
* D-Channel-up and B-Channel-up Messages.
* This function is initially called from within isdn_net_start_xmit() or
* or isdn_net_find_icall() after initializing the dialstate for an
* interface. If further calls are needed, the function schedules itself
* for a timer-callback via isdn_timer_function().
* The dialstate is also affected by incoming status-messages from
* the ISDN-Channel which are handled in isdn_net_stat_callback() above.
* Handle status-messages from ISDN-interfacecard.
* This function is called from within the main-status-dispatcher
* isdn_status_callback, which itself is called from the low-level driver.
* Return: 1 = Event handled, 0 = not for us or unknown Event.
*/
void
isdn_net_dial(void)
int
isdn_net_stat_callback(int idx, isdn_ctrl *c)
{
isdn_net_dev *p = dev->netdev;
int anymore = 0;
int i;
unsigned long flags;
isdn_ctrl cmd;
u_char *phone_number;
isdn_net_dev *p = isdn_slot_st_netdev(idx);
isdn_net_local *lp;
int cmd = c->command;
while (p) {
isdn_net_local *lp = p->local;
if (!p) {
HERE;
return 0;
}
lp = &p->local;
#ifdef ISDN_DEBUG_NET_DIAL
if (lp->dialstate)
printk(KERN_DEBUG "%s: dialstate=%d\n", lp->name, lp->dialstate);
#endif
switch (lp->dialstate) {
case 0:
/* Nothing to do for this interface */
break;
case 1:
/* Initiate dialout. Set phone-number-pointer to first number
return isdn_net_handle_event(lp, cmd, c);
}
static void
isdn_net_dial_timer(unsigned long data)
{
isdn_net_local *lp = (isdn_net_local *) data;
if (!lp) {
isdn_BUG();
return;
}
printk("%s: %s %#x\n", __FUNCTION__, lp->name, lp->dial_event);
isdn_net_handle_event(lp, lp->dial_event, NULL);
}
/* Initiate dialout. Set phone-number-pointer to first number
* of interface.
*/
static int
init_dialout(isdn_net_local *lp)
{
unsigned long flags;
save_flags(flags);
cli();
lp->dial = lp->phone[1];
restore_flags(flags);
if (!lp->dial) {
printk(KERN_WARNING "%s: phone number deleted?\n",
lp->name);
isdn_net_hangup(&p->dev);
break;
isdn_net_hangup(&lp->netdev->dev);
return 0;
}
anymore = 1;
if(lp->dialtimeout > 0)
if(lp->dialstarted == 0 || time_after(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait)) {
if (lp->dialtimeout > 0 &&
(lp->dialstarted == 0 ||
time_after(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait))) {
lp->dialstarted = jiffies;
lp->dialwait_timer = 0;
}
lp->dialstate++;
/* Fall through */
case 2:
/* Prepare dialing. Clear EAZ, then set EAZ. */
cmd.driver = lp->isdn_device;
cmd.arg = lp->isdn_channel;
cmd.command = ISDN_CMD_CLREAZ;
isdn_command(&cmd);
sprintf(cmd.parm.num, "%s", isdn_map_eaz2msn(lp->msn, cmd.driver));
cmd.command = ISDN_CMD_SETEAZ;
isdn_command(&cmd);
lp->dialretry = 0;
anymore = 1;
lp->dialstate++;
/* Fall through */
case 3:
/* Setup interface, dial current phone-number, switch to next number.
return do_dialout(lp);
}
/* Setup interface, dial current phone-number, switch to next number.
* If list of phone-numbers is exhausted, increment
* retry-counter.
*/
static int
do_dialout(isdn_net_local *lp)
{
unsigned long flags;
if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF)) {
char *s;
if (dev->global_flags & ISDN_GLOBAL_STOPPED)
s = "dial suppressed: isdn system stopped";
else
s = "dial suppressed: dialmode `off'";
isdn_net_unreachable(&p->dev, 0, s);
isdn_net_hangup(&p->dev);
break;
isdn_net_unreachable(&lp->netdev->dev, 0, s);
isdn_net_hangup(&lp->netdev->dev);
return 0;
}
cmd.driver = lp->isdn_device;
cmd.command = ISDN_CMD_SETL2;
cmd.arg = lp->isdn_channel + (lp->l2_proto << 8);
isdn_command(&cmd);
cmd.driver = lp->isdn_device;
cmd.command = ISDN_CMD_SETL3;
cmd.arg = lp->isdn_channel + (lp->l3_proto << 8);
isdn_command(&cmd);
cmd.driver = lp->isdn_device;
cmd.arg = lp->isdn_channel;
save_flags(flags);
cli();
if (!lp->dial) {
restore_flags(flags);
printk(KERN_WARNING "%s: phone number deleted?\n",
lp->name);
isdn_net_hangup(&p->dev);
break;
isdn_net_hangup(&lp->netdev->dev);
return 0;
}
if (!strncmp(lp->dial->num, "LEASED", strlen("LEASED"))) {
restore_flags(flags);
lp->dialstate = 4;
lp->dialstate = ST_OUT_WAIT_DCONN;
printk(KERN_INFO "%s: Open leased line ...\n", lp->name);
return 1;
} else {
if(lp->dialtimeout > 0)
struct dial_info dial = {
.l2_proto = lp->l2_proto,
.l3_proto = lp->l3_proto,
.si1 = 7,
.si2 = 0,
.msn = lp->msn,
.phone = lp->dial->num,
};
if(lp->dialtimeout > 0) {
if (time_after(jiffies, lp->dialstarted + lp->dialtimeout)) {
restore_flags(flags);
lp->dialwait_timer = jiffies + lp->dialwait;
lp->dialstarted = 0;
isdn_net_unreachable(&p->dev, 0, "dial: timed out");
isdn_net_hangup(&p->dev);
break;
isdn_net_unreachable(&lp->netdev->dev, 0, "dial: timed out");
isdn_net_hangup(&lp->netdev->dev);
return 0;
}
cmd.driver = lp->isdn_device;
cmd.command = ISDN_CMD_DIAL;
cmd.parm.setup.si2 = 0;
/* check for DOV */
phone_number = lp->dial->num;
if ((*phone_number == 'v') ||
(*phone_number == 'V')) { /* DOV call */
cmd.parm.setup.si1 = 1;
} else { /* DATA call */
cmd.parm.setup.si1 = 7;
}
strcpy(cmd.parm.setup.phone, phone_number);
/*
* Switch to next number or back to start if at end of list.
*/
......@@ -702,30 +597,14 @@ isdn_net_dial(void)
if (lp->dialtimeout == 0) {
lp->dialwait_timer = jiffies + lp->dialwait;
lp->dialstarted = 0;
isdn_net_unreachable(&p->dev, 0, "dial: tried all numbers dialmax times");
isdn_net_unreachable(&lp->netdev->dev, 0, "dial: tried all numbers dialmax times");
}
isdn_net_hangup(&p->dev);
break;
isdn_net_hangup(&lp->netdev->dev);
return 0;
}
}
restore_flags(flags);
sprintf(cmd.parm.setup.eazmsn, "%s",
isdn_map_eaz2msn(lp->msn, cmd.driver));
i = isdn_dc2minor(lp->isdn_device, lp->isdn_channel);
if (i >= 0) {
strcpy(dev->num[i], cmd.parm.setup.phone);
dev->usage[i] |= ISDN_USAGE_OUTGOING;
isdn_info_update();
}
printk(KERN_INFO "%s: dialing %d %s... %s\n", lp->name,
lp->dialretry, cmd.parm.setup.phone,
(cmd.parm.setup.si1 == 1) ? "DOV" : "");
lp->dtimer = 0;
#ifdef ISDN_DEBUG_NET_DIAL
printk(KERN_DEBUG "dial: d=%d c=%d\n", lp->isdn_device,
lp->isdn_channel);
#endif
isdn_command(&cmd);
isdn_slot_dial(lp->isdn_slot, &dial);
}
lp->huptimer = 0;
lp->outgoing = 1;
......@@ -736,114 +615,205 @@ isdn_net_dial(void)
lp->hupflags |= ISDN_WAITCHARGE;
lp->hupflags &= ~ISDN_HAVECHARGE;
}
anymore = 1;
lp->dialstate =
(lp->cbdelay &&
(lp->flags & ISDN_NET_CBOUT)) ? 12 : 4;
if (lp->cbdelay && (lp->flags & ISDN_NET_CBOUT)) {
lp->dial_timer.expires = jiffies + lp->cbdelay;
lp->dial_event = EV_NET_TIMER_CB;
} else {
lp->dial_timer.expires = jiffies + 10 * HZ;
lp->dial_event = EV_NET_TIMER_OUT_DCONN;
}
lp->dialstate = ST_OUT_WAIT_DCONN;
add_timer(&lp->dial_timer);
return 1;
}
/* For EV_NET_DIAL, returns 1 if timer callback is needed
* For ISDN_STAT_*, returns 1 if event was for us
*/
static int
isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg)
{
#ifdef CONFIG_ISDN_X25
struct concap_proto *cprot = lp -> netdev -> cprot;
struct concap_proto_ops *pops = cprot ? cprot -> pops : 0;
#endif
isdn_net_dev *p = lp->netdev;
isdn_ctrl *c = arg;
isdn_ctrl cmd;
dbg_net_dial("%s: dialstate=%d pr=%#x\n", lp->name, lp->dialstate,pr);
switch (lp->dialstate) {
case ST_ACTIVE:
switch (pr) {
case ISDN_STAT_BSENT:
/* A packet has successfully been sent out */
if (lp->flags & ISDN_NET_CONNECTED) {
isdn_net_dec_frame_cnt(lp);
lp->stats.tx_packets++;
lp->stats.tx_bytes += c->parm.length;
return 1;
}
break;
case 4:
/* Wait for D-Channel-connect.
* If timeout, switch back to state 3.
* Dialmax-handling moved to state 3.
case ISDN_STAT_DHUP:
/* Either D-Channel-hangup or error during dialout */
#ifdef CONFIG_ISDN_X25 // FIXME handle != ST_0?
/* If we are not connencted then dialing had
failed. If there are generic encap protocol
receiver routines signal the closure of
the link*/
if (!(lp->flags & ISDN_NET_CONNECTED)
&& pops && pops->disconn_ind)
pops -> disconn_ind(cprot);
#endif /* CONFIG_ISDN_X25 */
if (lp->flags & ISDN_NET_CONNECTED) {
if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
isdn_net_ciscohdlck_disconnected(lp);
#ifdef CONFIG_ISDN_PPP
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
isdn_ppp_free(lp);
#endif
isdn_net_lp_disconnected(lp);
isdn_slot_all_eaz(lp->isdn_slot);
printk(KERN_INFO "%s: remote hangup\n", lp->name);
printk(KERN_INFO "%s: Chargesum is %d\n", lp->name,
lp->charge);
isdn_net_unbind_channel(lp);
return 1;
}
break;
#ifdef CONFIG_ISDN_X25 // FIXME handle != ST_0?
case ISDN_STAT_BHUP:
/* B-Channel-hangup */
/* try if there are generic encap protocol
receiver routines and signal the closure of
the link */
if( pops && pops -> disconn_ind ){
pops -> disconn_ind(cprot);
return 1;
}
break;
#endif /* CONFIG_ISDN_X25 */
case ISDN_STAT_CINF:
/* Charge-info from TelCo. Calculate interval between
* charge-infos and set timestamp for last info for
* usage by isdn_net_autohup()
*/
if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
lp->dialstate = 3;
anymore = 1;
lp->charge++;
if (lp->hupflags & ISDN_HAVECHARGE) {
lp->hupflags &= ~ISDN_WAITCHARGE;
lp->chargeint = jiffies - lp->chargetime - (2 * HZ);
}
if (lp->hupflags & ISDN_WAITCHARGE)
lp->hupflags |= ISDN_HAVECHARGE;
lp->chargetime = jiffies;
printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %lu\n",
lp->name, lp->chargetime);
return 1;
}
break;
case 5:
case ST_OUT_WAIT_DCONN:
switch (pr) {
case EV_NET_TIMER_OUT_DCONN:
/* try again */
do_dialout(lp);
return 1;
case EV_NET_TIMER_CB:
/* Remote does callback. Hangup after cbdelay,
* then wait for incoming call */
printk(KERN_INFO "%s: hangup waiting for callback ...\n", lp->name);
isdn_net_hangup(&lp->netdev->dev);
return 1;
case ISDN_STAT_DCONN:
/* Got D-Channel-Connect, send B-Channel-request */
cmd.driver = lp->isdn_device;
cmd.arg = lp->isdn_channel;
cmd.command = ISDN_CMD_ACCEPTB;
anymore = 1;
lp->dtimer = 0;
lp->dialstate++;
isdn_command(&cmd);
del_timer(&lp->dial_timer);
lp->dialstate = ST_OUT_WAIT_BCONN;
isdn_slot_command(lp->isdn_slot, ISDN_CMD_ACCEPTB, &cmd);
lp->dial_timer.expires = jiffies + 10 * HZ;
lp->dial_event = EV_NET_TIMER_OUT_BCONN;
add_timer(&lp->dial_timer);
return 1;
case ISDN_STAT_DHUP:
del_timer(&lp->dial_timer);
isdn_slot_all_eaz(lp->isdn_slot);
printk(KERN_INFO "%s: remote hangup\n", lp->name);
isdn_net_unbind_channel(lp);
return 1;
}
break;
case 6:
/* Wait for B- or D-Channel-connect. If timeout,
* switch back to state 3.
*/
#ifdef ISDN_DEBUG_NET_DIAL
printk(KERN_DEBUG "dialtimer2: %d\n", lp->dtimer);
#endif
if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
lp->dialstate = 3;
anymore = 1;
case ST_OUT_WAIT_BCONN:
switch (pr) {
case EV_NET_TIMER_OUT_BCONN:
/* try again */
do_dialout(lp);
return 1;
case ISDN_STAT_BCONN:
del_timer(&lp->dial_timer);
isdn_slot_set_usage(lp->isdn_slot, isdn_slot_usage(lp->isdn_slot) | ISDN_USAGE_OUTGOING);
isdn_net_connected(lp);
return 1;
case ISDN_STAT_DHUP:
del_timer(&lp->dial_timer);
isdn_slot_all_eaz(lp->isdn_slot);
printk(KERN_INFO "%s: remote hangup\n", lp->name);
isdn_net_unbind_channel(lp);
return 1;
}
break;
case 7:
/* Got incoming Call, setup L2 and L3 protocols,
* then wait for D-Channel-connect
*/
#ifdef ISDN_DEBUG_NET_DIAL
printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer);
#endif
cmd.driver = lp->isdn_device;
cmd.command = ISDN_CMD_SETL2;
cmd.arg = lp->isdn_channel + (lp->l2_proto << 8);
isdn_command(&cmd);
cmd.driver = lp->isdn_device;
cmd.command = ISDN_CMD_SETL3;
cmd.arg = lp->isdn_channel + (lp->l3_proto << 8);
isdn_command(&cmd);
if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT15)
case ST_IN_WAIT_DCONN:
switch (pr) {
case EV_NET_TIMER_IN_DCONN:
isdn_net_hangup(&p->dev);
else {
anymore = 1;
lp->dialstate++;
return 1;
case ISDN_STAT_DCONN:
del_timer(&lp->dial_timer);
lp->dialstate = ST_IN_WAIT_BCONN;
isdn_slot_command(lp->isdn_slot, ISDN_CMD_ACCEPTB, &cmd);
lp->dial_timer.expires = jiffies + 10 * HZ;
lp->dial_event = EV_NET_TIMER_IN_BCONN;
add_timer(&lp->dial_timer);
return 1;
case ISDN_STAT_DHUP:
del_timer(&lp->dial_timer);
isdn_slot_all_eaz(lp->isdn_slot);
printk(KERN_INFO "%s: remote hangup\n", lp->name);
isdn_net_unbind_channel(lp);
return 1;
}
break;
case 9:
/* Got incoming D-Channel-Connect, send B-Channel-request */
cmd.driver = lp->isdn_device;
cmd.arg = lp->isdn_channel;
cmd.command = ISDN_CMD_ACCEPTB;
isdn_command(&cmd);
anymore = 1;
lp->dtimer = 0;
lp->dialstate++;
break;
case 8:
case 10:
/* Wait for B- or D-channel-connect */
#ifdef ISDN_DEBUG_NET_DIAL
printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer);
#endif
if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
case ST_IN_WAIT_BCONN:
switch (pr) {
case EV_NET_TIMER_IN_BCONN:
isdn_net_hangup(&p->dev);
else
anymore = 1;
break;
case 11:
/* Callback Delay */
if (lp->dtimer++ > lp->cbdelay)
lp->dialstate = 1;
anymore = 1;
case ISDN_STAT_BCONN:
del_timer(&lp->dial_timer);
isdn_slot_set_rx_netdev(lp->isdn_slot, p);
isdn_net_connected(lp);
return 1;
case ISDN_STAT_DHUP:
del_timer(&lp->dial_timer);
isdn_slot_all_eaz(lp->isdn_slot);
printk(KERN_INFO "%s: remote hangup\n", lp->name);
isdn_net_unbind_channel(lp);
return 1;
}
break;
case 12:
/* Remote does callback. Hangup after cbdelay, then wait for incoming
* call (in state 4).
*/
if (lp->dtimer++ > lp->cbdelay)
{
printk(KERN_INFO "%s: hangup waiting for callback ...\n", lp->name);
lp->dtimer = 0;
lp->dialstate = 4;
cmd.driver = lp->isdn_device;
cmd.command = ISDN_CMD_HANGUP;
cmd.arg = lp->isdn_channel;
isdn_command(&cmd);
isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
case ST_WAIT_BEFORE_CB:
switch (pr) {
case EV_NET_TIMER_CB:
/* Callback Delay */
init_dialout(lp);
return 1;
}
anymore = 1;
break;
default:
printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n",
lp->dialstate, lp->name);
}
p = (isdn_net_dev *) p->next;
isdn_BUG();
break;
}
isdn_timer_ctrl(ISDN_TIMER_NETDIAL, anymore);
printk("NOT HANDLED?\n");
return 0;
}
/*
......@@ -883,12 +853,9 @@ isdn_net_hangup(struct net_device *d)
pops -> disconn_ind(cprot);
#endif /* CONFIG_ISDN_X25 */
cmd.driver = lp->isdn_device;
cmd.command = ISDN_CMD_HANGUP;
cmd.arg = lp->isdn_channel;
isdn_command(&cmd);
isdn_slot_command(lp->isdn_slot, ISDN_CMD_HANGUP, &cmd);
printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, lp->charge);
isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
isdn_slot_all_eaz(lp->isdn_slot);
}
isdn_net_unbind_channel(lp);
}
......@@ -1041,15 +1008,15 @@ void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb)
/* before obtaining the lock the caller should have checked that
the lp isn't busy */
if (isdn_net_lp_busy(lp)) {
printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
isdn_BUG();
goto error;
}
if (!(lp->flags & ISDN_NET_CONNECTED)) {
printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
isdn_BUG();
goto error;
}
ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
ret = isdn_slot_write(lp->isdn_slot, skb);
if (ret != len) {
/* we should never get here */
printk(KERN_WARNING "%s: HL driver queue full\n", lp->name);
......@@ -1137,7 +1104,7 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
lp->sqfull = 0;
}
/* this is a hack to allow auto-hangup for slaves on moderate loads */
nd->queue = nd->local;
nd->queue = &nd->local;
}
return retv;
......@@ -1165,7 +1132,7 @@ void isdn_net_tx_timeout(struct net_device * ndev)
isdn_net_local *lp = (isdn_net_local *) ndev->priv;
printk(KERN_WARNING "isdn_tx_timeout dev %s dialstate %d\n", ndev->name, lp->dialstate);
if (!lp->dialstate){
if (lp->dialstate == ST_ACTIVE){
lp->stats.tx_errors++;
/*
* There is a certain probability that this currently
......@@ -1220,14 +1187,8 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
#endif
/* auto-dialing xmit function */
{
#ifdef ISDN_DEBUG_NET_DUMP
u_char *buf;
#endif
isdn_net_adjust_hdr(skb, ndev);
#ifdef ISDN_DEBUG_NET_DUMP
buf = skb->data;
isdn_dumppkt("S:", buf, skb->len, 40);
#endif
isdn_dumppkt("S:", skb->data, skb->len, 40);
if (!(lp->flags & ISDN_NET_CONNECTED)) {
int chi;
......@@ -1257,7 +1218,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
}
/* Grab a free ISDN-Channel */
if (((chi =
isdn_get_free_channel(
isdn_get_free_slot(
ISDN_USAGE_NET,
lp->l2_proto,
lp->l3_proto,
......@@ -1266,7 +1227,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
lp->msn)
) < 0) &&
((chi =
isdn_get_free_channel(
isdn_get_free_slot(
ISDN_USAGE_NET,
lp->l2_proto,
lp->l3_proto,
......@@ -1283,7 +1244,6 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
/* Log packet, which triggered dialing */
if (dev->net_verbose)
isdn_net_log_skb(skb, lp);
lp->dialstate = 1;
/* Connect interface with channel */
isdn_net_bind_channel(lp, chi);
#ifdef CONFIG_ISDN_PPP
......@@ -1296,14 +1256,14 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
return 0; /* STN (skb to nirvana) ;) */
}
restore_flags(flags);
isdn_net_dial(); /* Initiate dialing */
init_dialout(lp);
netif_stop_queue(ndev);
return 1; /* let upper layer requeue skb packet */
}
#endif
/* Initiate dialing */
restore_flags(flags);
isdn_net_dial();
init_dialout(lp);
isdn_net_device_stop_queue(lp);
return 1;
} else {
......@@ -1315,7 +1275,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
} else {
/* Device is connected to an ISDN channel */
ndev->trans_start = jiffies;
if (!lp->dialstate) {
if (lp->dialstate == ST_ACTIVE) {
/* ISDN connection is established, try sending */
int ret;
ret = (isdn_net_xmit(ndev, skb));
......@@ -1433,7 +1393,7 @@ isdn_net_type_trans(struct sk_buff *skb, struct net_device *dev)
static struct sk_buff*
isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len)
{
unsigned short hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
unsigned short hl = isdn_slot_hdrlen(lp->isdn_slot);
struct sk_buff *skb;
skb = alloc_skb(hl + len, GFP_ATOMIC);
......@@ -1523,8 +1483,8 @@ isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
unsigned long last_cisco_myseq = lp->cisco_myseq;
int myseq_diff = 0;
if (!(lp->flags & ISDN_NET_CONNECTED) || lp->dialstate) {
printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
if (!(lp->flags & ISDN_NET_CONNECTED) || lp->dialstate != ST_ACTIVE) {
isdn_BUG();
return;
}
lp->cisco_myseq++;
......@@ -1814,9 +1774,7 @@ isdn_net_receive(struct net_device *ndev, struct sk_buff *skb)
skb->dev = ndev;
skb->pkt_type = PACKET_HOST;
skb->mac.raw = skb->data;
#ifdef ISDN_DEBUG_NET_DUMP
isdn_dumppkt("R:", skb->data, skb->len, 40);
#endif
switch (lp->p_encap) {
case ISDN_NET_ENCAP_ETHER:
/* Ethernet over ISDN */
......@@ -1893,12 +1851,12 @@ isdn_net_receive(struct net_device *ndev, struct sk_buff *skb)
int
isdn_net_rcv_skb(int idx, struct sk_buff *skb)
{
isdn_net_dev *p = dev->rx_netdev[idx];
isdn_net_dev *p = isdn_slot_rx_netdev(idx);
if (p) {
isdn_net_local *lp = p->local;
isdn_net_local *lp = &p->local;
if ((lp->flags & ISDN_NET_CONNECTED) &&
(!lp->dialstate)) {
(lp->dialstate == ST_ACTIVE)) {
isdn_net_receive(&p->dev, skb);
return 1;
}
......@@ -2093,40 +2051,34 @@ isdn_net_init(struct net_device *ndev)
static void
isdn_net_swapbind(int drvidx)
{
isdn_net_dev *p;
struct list_head *l;
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: swapping ch of %d\n", drvidx);
#endif
p = dev->netdev;
while (p) {
if (p->local->pre_device == drvidx)
switch (p->local->pre_channel) {
dbg_net_icall("n_fi: swapping ch of %d\n", drvidx);
list_for_each(l, &isdn_net_devs) {
isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
if (p->local.pre_device != drvidx)
continue;
switch (p->local.pre_channel) {
case 0:
p->local->pre_channel = 1;
p->local.pre_channel = 1;
break;
case 1:
p->local->pre_channel = 0;
p->local.pre_channel = 0;
break;
}
p = (isdn_net_dev *) p->next;
}
}
static void
isdn_net_swap_usage(int i1, int i2)
{
int u1 = dev->usage[i1] & ISDN_USAGE_EXCLUSIVE;
int u2 = dev->usage[i2] & ISDN_USAGE_EXCLUSIVE;
int u1 = isdn_slot_usage(i1);
int u2 = isdn_slot_usage(i2);
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: usage of %d and %d\n", i1, i2);
#endif
dev->usage[i1] &= ~ISDN_USAGE_EXCLUSIVE;
dev->usage[i1] |= u2;
dev->usage[i2] &= ~ISDN_USAGE_EXCLUSIVE;
dev->usage[i2] |= u1;
isdn_info_update();
dbg_net_icall("n_fi: usage of %d and %d\n", i1, i2);
isdn_slot_set_usage(i1, (u1 & ~ISDN_USAGE_EXCLUSIVE) | (u2 & ISDN_USAGE_EXCLUSIVE));
isdn_slot_set_usage(i2, (u2 & ~ISDN_USAGE_EXCLUSIVE) | (u1 & ISDN_USAGE_EXCLUSIVE));
}
/*
......@@ -2155,12 +2107,14 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
int wret;
int swapped;
int sidx = 0;
isdn_net_dev *p;
struct list_head *l;
isdn_net_phone *n;
ulong flags;
char nr[32];
char *my_eaz;
isdn_ctrl cmd;
int slot = isdn_dc2minor(di, ch);
/* Search name in netdev-chain */
save_flags(flags);
cli();
......@@ -2188,16 +2142,15 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
return 0;
}
n = (isdn_net_phone *) 0;
p = dev->netdev;
n = (isdn_net_phone *) 0;
ematch = wret = swapped = 0;
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: di=%d ch=%d idx=%d usg=%d\n", di, ch, idx,
dev->usage[idx]);
#endif
while (p) {
dbg_net_icall("n_fi: di=%d ch=%d idx=%d usg=%d\n", di, ch, idx,
isdn_slot_usage(idx));
list_for_each(l, &isdn_net_devs) {
int matchret;
isdn_net_local *lp = p->local;
isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
isdn_net_local *lp = &p->local;
/* If last check has triggered as binding-swap, revert it */
switch (swapped) {
......@@ -2210,7 +2163,7 @@ p = dev->netdev;
}
swapped = 0;
/* check acceptable call types for DOV */
my_eaz = isdn_map_eaz2msn(lp->msn, di);
my_eaz = isdn_slot_map_eaz2msn(slot, lp->msn);
if (si1 == 1) { /* it's a DOV call, check if we allow it */
if (*my_eaz == 'v' || *my_eaz == 'V' ||
*my_eaz == 'b' || *my_eaz == 'B')
......@@ -2231,22 +2184,18 @@ p = dev->netdev;
/* Remember if more numbers eventually can match */
if (matchret > wret)
wret = matchret;
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n",
dbg_net_icall("n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n",
lp->name, lp->msn, lp->flags, lp->dialstate);
#endif
if ((!matchret) && /* EAZ is matching */
(((!(lp->flags & ISDN_NET_CONNECTED)) && /* but not connected */
(USG_NONE(dev->usage[idx]))) || /* and ch. unused or */
((((lp->dialstate == 4) || (lp->dialstate == 12)) && /* if dialing */
(USG_NONE(isdn_slot_usage(idx)))) || /* and ch. unused or */
((((lp->dialstate == ST_OUT_WAIT_DCONN) || (lp->dialstate == ST_OUT_WAIT_DCONN)) && /* if dialing */
(!(lp->flags & ISDN_NET_CALLBACK))) /* but no callback */
)))
{
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: match1, pdev=%d pch=%d\n",
dbg_net_icall("n_fi: match1, pdev=%d pch=%d\n",
lp->pre_device, lp->pre_channel);
#endif
if (dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) {
if (isdn_slot_usage(idx) & ISDN_USAGE_EXCLUSIVE) {
if ((lp->pre_channel != ch) ||
(lp->pre_device != di)) {
/* Here we got a problem:
......@@ -2260,16 +2209,12 @@ p = dev->netdev;
*/
if (ch == 0) {
sidx = isdn_dc2minor(di, 1);
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: ch is 0\n");
#endif
if (USG_NONE(dev->usage[sidx])) {
dbg_net_icall("n_fi: ch is 0\n");
if (USG_NONE(isdn_slot_usage(sidx))) {
/* Second Channel is free, now see if it is bound
* exclusive too. */
if (dev->usage[sidx] & ISDN_USAGE_EXCLUSIVE) {
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: 2nd channel is down and bound\n");
#endif
if (isdn_slot_usage(sidx) & ISDN_USAGE_EXCLUSIVE) {
dbg_net_icall("n_fi: 2nd channel is down and bound\n");
/* Yes, swap bindings only, if the original
* binding is bound to channel 1 of this driver */
if ((lp->pre_device == di) &&
......@@ -2278,43 +2223,31 @@ p = dev->netdev;
swapped = 1;
} else {
/* ... else iterate next device */
p = (isdn_net_dev *) p->next;
continue;
}
} else {
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: 2nd channel is down and unbound\n");
#endif
dbg_net_icall("n_fi: 2nd channel is down and unbound\n");
/* No, swap always and swap excl-usage also */
isdn_net_swap_usage(idx, sidx);
isdn_net_swapbind(di);
swapped = 2;
}
/* Now check for exclusive binding again */
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: final check\n");
#endif
if ((dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) &&
dbg_net_icall("n_fi: final check\n");
if ((isdn_slot_usage(idx) & ISDN_USAGE_EXCLUSIVE) &&
((lp->pre_channel != ch) ||
(lp->pre_device != di))) {
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: final check failed\n");
#endif
p = (isdn_net_dev *) p->next;
dbg_net_icall("n_fi: final check failed\n");
continue;
}
}
} else {
/* We are already on the second channel, so nothing to do */
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: already on 2nd channel\n");
#endif
dbg_net_icall("n_fi: already on 2nd channel\n");
}
}
}
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: match2\n");
#endif
dbg_net_icall("n_fi: match2\n");
n = lp->phone[0];
if (lp->flags & ISDN_NET_SECURE) {
while (n) {
......@@ -2324,9 +2257,7 @@ p = dev->netdev;
}
}
if (n || (!(lp->flags & ISDN_NET_SECURE))) {
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: match3\n");
#endif
dbg_net_icall("n_fi: match3\n");
/* matching interface found */
/*
......@@ -2370,7 +2301,6 @@ p = dev->netdev;
/* Found parent, if it's offline iterate next device */
printk(KERN_DEBUG "mlpf: %d\n", mlp->flags & ISDN_NET_CONNECTED);
if (!(mlp->flags & ISDN_NET_CONNECTED)) {
p = (isdn_net_dev *) p->next;
continue;
}
}
......@@ -2392,7 +2322,7 @@ p = dev->netdev;
if (lp->phone[1]) {
/* Grab a free ISDN-Channel */
if ((chi =
isdn_get_free_channel(
isdn_get_free_slot(
ISDN_USAGE_NET,
lp->l2_proto,
lp->l3_proto,
......@@ -2406,8 +2336,11 @@ p = dev->netdev;
return 0;
}
/* Setup dialstate. */
lp->dtimer = 0;
lp->dialstate = 11;
lp->dial_timer.expires = jiffies + lp->cbdelay;
lp->dial_event = EV_NET_TIMER_CB;
add_timer(&lp->dial_timer);
lp->dialstate = ST_WAIT_BEFORE_CB;
/* Connect interface with channel */
isdn_net_bind_channel(lp, chi);
#ifdef CONFIG_ISDN_PPP
......@@ -2430,30 +2363,39 @@ p = dev->netdev;
eaz);
/* if this interface is dialing, it does it probably on a different
device, so free this device */
if ((lp->dialstate == 4) || (lp->dialstate == 12)) {
if (lp->dialstate == ST_OUT_WAIT_DCONN) {
#ifdef CONFIG_ISDN_PPP
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
isdn_ppp_free(lp);
#endif
isdn_net_lp_disconnected(lp);
isdn_free_channel(lp->isdn_device, lp->isdn_channel,
isdn_slot_free(lp->isdn_slot,
ISDN_USAGE_NET);
}
dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
dev->usage[idx] |= ISDN_USAGE_NET;
strcpy(dev->num[idx], nr);
isdn_info_update();
dev->st_netdev[idx] = lp->netdev;
lp->isdn_device = di;
lp->isdn_channel = ch;
strcpy(isdn_slot_num(idx), nr);
isdn_slot_set_usage(idx, (isdn_slot_usage(idx) & ISDN_USAGE_EXCLUSIVE) | ISDN_USAGE_NET);
isdn_slot_set_st_netdev(idx, lp->netdev);
lp->isdn_slot = slot;
lp->ppp_slot = -1;
lp->flags |= ISDN_NET_CONNECTED;
lp->dialstate = 7;
lp->dtimer = 0;
lp->outgoing = 0;
lp->huptimer = 0;
lp->hupflags |= ISDN_WAITCHARGE;
lp->hupflags &= ~ISDN_HAVECHARGE;
/* Got incoming Call, setup L2 and L3 protocols,
* then wait for D-Channel-connect
*/
cmd.arg = lp->l2_proto << 8;
isdn_slot_command(lp->isdn_slot, ISDN_CMD_SETL2, &cmd);
cmd.arg = lp->l3_proto << 8;
isdn_slot_command(lp->isdn_slot, ISDN_CMD_SETL3, &cmd);
lp->dial_timer.expires = jiffies + 15 * HZ;
lp->dial_event = EV_NET_TIMER_IN_DCONN;
add_timer(&lp->dial_timer);
lp->dialstate = ST_IN_WAIT_DCONN;
#ifdef CONFIG_ISDN_PPP
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
if (isdn_ppp_bind(lp) < 0) {
......@@ -2467,11 +2409,10 @@ p = dev->netdev;
}
}
}
p = (isdn_net_dev *) p->next;
}
/* If none of configured EAZ/MSN matched and not verbose, be silent */
if (!ematch || dev->net_verbose)
printk(KERN_INFO "isdn_net: call from %s -> %d %s ignored\n", nr, di, eaz);
printk(KERN_INFO "isdn_net: call from %s -> %d %s ignored\n", nr, slot, eaz);
restore_flags(flags);
return (wret == 2)?5:0;
}
......@@ -2482,14 +2423,14 @@ p = dev->netdev;
isdn_net_dev *
isdn_net_findif(char *name)
{
isdn_net_dev *p = dev->netdev;
struct list_head *l;
while (p) {
if (!strcmp(p->local->name, name))
list_for_each(l, &isdn_net_devs) {
isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
if (!strcmp(p->local.name, name))
return p;
p = (isdn_net_dev *) p->next;
}
return (isdn_net_dev *) NULL;
return NULL;
}
/*
......@@ -2500,7 +2441,7 @@ isdn_net_findif(char *name)
int
isdn_net_force_dial_lp(isdn_net_local * lp)
{
if ((!(lp->flags & ISDN_NET_CONNECTED)) && !lp->dialstate) {
if ((!(lp->flags & ISDN_NET_CONNECTED)) && lp->dialstate == ST_NULL) {
int chi;
if (lp->phone[1]) {
ulong flags;
......@@ -2509,7 +2450,7 @@ isdn_net_force_dial_lp(isdn_net_local * lp)
/* Grab a free ISDN-Channel */
if ((chi =
isdn_get_free_channel(
isdn_get_free_slot(
ISDN_USAGE_NET,
lp->l2_proto,
lp->l3_proto,
......@@ -2521,7 +2462,6 @@ isdn_net_force_dial_lp(isdn_net_local * lp)
restore_flags(flags);
return -EAGAIN;
}
lp->dialstate = 1;
/* Connect interface with channel */
isdn_net_bind_channel(lp, chi);
#ifdef CONFIG_ISDN_PPP
......@@ -2534,7 +2474,7 @@ isdn_net_force_dial_lp(isdn_net_local * lp)
#endif
/* Initiate dialing */
restore_flags(flags);
isdn_net_dial();
init_dialout(lp);
return 0;
} else
return -EINVAL;
......@@ -2567,47 +2507,39 @@ isdn_net_force_dial(char *name)
if (!p)
return -ENODEV;
return (isdn_net_force_dial_lp(p->local));
return (isdn_net_force_dial_lp(&p->local));
}
/*
* Allocate a new network-interface and initialize its data structures.
*/
char *
int
isdn_net_new(char *name, struct net_device *master)
{
int retval;
isdn_net_dev *netdev;
/* Avoid creating an existing interface */
if (isdn_net_findif(name)) {
printk(KERN_WARNING "isdn_net: interface %s already exists\n", name);
return NULL;
return -EEXIST;
}
if (!(netdev = (isdn_net_dev *) kmalloc(sizeof(isdn_net_dev), GFP_KERNEL))) {
if (!(netdev = kmalloc(sizeof(isdn_net_dev), GFP_KERNEL))) {
printk(KERN_WARNING "isdn_net: Could not allocate net-device\n");
return NULL;
return -ENOMEM;
}
memset(netdev, 0, sizeof(isdn_net_dev));
if (!(netdev->local = (isdn_net_local *) kmalloc(sizeof(isdn_net_local), GFP_KERNEL))) {
printk(KERN_WARNING "isdn_net: Could not allocate device locals\n");
kfree(netdev);
return NULL;
}
memset(netdev->local, 0, sizeof(isdn_net_local));
if (name == NULL)
strcpy(netdev->local->name, " ");
else
strcpy(netdev->local->name, name);
strcpy(netdev->dev.name, netdev->local->name);
netdev->dev.priv = netdev->local;
strcpy(netdev->local.name, name);
strcpy(netdev->dev.name, name);
netdev->dev.priv = &netdev->local;
netdev->dev.init = isdn_net_init;
netdev->local->p_encap = ISDN_NET_ENCAP_RAWIP;
netdev->local.p_encap = ISDN_NET_ENCAP_RAWIP;
if (master) {
/* Device shall be a slave */
struct net_device *p = (((isdn_net_local *) master->priv)->slave);
struct net_device *q = master;
netdev->local->master = master;
netdev->local.master = master;
/* Put device at end of slave-chain */
while (p) {
q = p;
......@@ -2621,81 +2553,80 @@ isdn_net_new(char *name, struct net_device *master)
*/
netdev->dev.tx_timeout = isdn_net_tx_timeout;
netdev->dev.watchdog_timeo = ISDN_NET_TX_TIMEOUT;
if (register_netdev(&netdev->dev) != 0) {
retval = register_netdev(&netdev->dev);
if (retval) {
printk(KERN_WARNING "isdn_net: Could not register net-device\n");
kfree(netdev->local);
kfree(netdev);
return NULL;
return retval;
}
}
netdev->local->magic = ISDN_NET_MAGIC;
netdev->local.magic = ISDN_NET_MAGIC;
netdev->queue = netdev->local;
netdev->queue = &netdev->local;
spin_lock_init(&netdev->queue_lock);
netdev->local->last = netdev->local;
netdev->local->netdev = netdev;
netdev->local->next = netdev->local;
netdev->local->tqueue.sync = 0;
netdev->local->tqueue.routine = isdn_net_softint;
netdev->local->tqueue.data = netdev->local;
spin_lock_init(&netdev->local->xmit_lock);
netdev->local->isdn_device = -1;
netdev->local->isdn_channel = -1;
netdev->local->pre_device = -1;
netdev->local->pre_channel = -1;
netdev->local->exclusive = -1;
netdev->local->ppp_slot = -1;
netdev->local->pppbind = -1;
skb_queue_head_init(&netdev->local->super_tx_queue);
netdev->local->l2_proto = ISDN_PROTO_L2_X75I;
netdev->local->l3_proto = ISDN_PROTO_L3_TRANS;
netdev->local->triggercps = 6000;
netdev->local->slavedelay = 10 * HZ;
netdev->local->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */
netdev->local->onhtime = 10; /* Default hangup-time for saving costs
netdev->local.last = &netdev->local;
netdev->local.netdev = netdev;
netdev->local.next = &netdev->local;
netdev->local.tqueue.sync = 0;
netdev->local.tqueue.routine = isdn_net_softint;
netdev->local.tqueue.data = &netdev->local;
spin_lock_init(&netdev->local.xmit_lock);
netdev->local.isdn_slot = -1;
netdev->local.pre_device = -1;
netdev->local.pre_channel = -1;
netdev->local.exclusive = -1;
netdev->local.ppp_slot = -1;
netdev->local.pppbind = -1;
skb_queue_head_init(&netdev->local.super_tx_queue);
netdev->local.l2_proto = ISDN_PROTO_L2_X75I;
netdev->local.l3_proto = ISDN_PROTO_L3_TRANS;
netdev->local.triggercps = 6000;
netdev->local.slavedelay = 10 * HZ;
netdev->local.hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */
netdev->local.onhtime = 10; /* Default hangup-time for saving costs
of those who forget configuring this */
netdev->local->dialmax = 1;
netdev->local->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL; /* Hangup before Callback, manual dial */
netdev->local->cbdelay = 25; /* Wait 5 secs before Callback */
netdev->local->dialtimeout = -1; /* Infinite Dial-Timeout */
netdev->local->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */
netdev->local->dialstarted = 0; /* Jiffies of last dial-start */
netdev->local->dialwait_timer = 0; /* Jiffies of earliest next dial-start */
netdev->local.dialmax = 1;
netdev->local.flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL; /* Hangup before Callback, manual dial */
netdev->local.cbdelay = 5 * HZ; /* Wait 5 secs before Callback */
netdev->local.dialtimeout = -1; /* Infinite Dial-Timeout */
netdev->local.dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */
netdev->local.dialstarted = 0; /* Jiffies of last dial-start */
netdev->local.dialwait_timer = 0; /* Jiffies of earliest next dial-start */
init_timer(&netdev->local.dial_timer);
netdev->local.dial_timer.data = (unsigned long) &netdev->local;
netdev->local.dial_timer.function = isdn_net_dial_timer;
/* Put into to netdev-chain */
netdev->next = (void *) dev->netdev;
dev->netdev = netdev;
return netdev->dev.name;
list_add(&netdev->global_list, &isdn_net_devs);
return 0;
}
char *
int
isdn_net_newslave(char *parm)
{
char *p = strchr(parm, ',');
isdn_net_dev *n;
char newname[10];
isdn_net_dev *m;
if (p) {
/* Slave-Name MUST not be empty */
if (!strlen(p + 1))
return NULL;
strcpy(newname, p + 1);
if (!p || !p[1])
return -EINVAL;
*p = 0;
/* Master must already exist */
if (!(n = isdn_net_findif(parm)))
return NULL;
if (!(m = isdn_net_findif(parm)))
return -ESRCH;
/* Master must be a real interface, not a slave */
if (n->local->master)
return NULL;
if (m->local.master)
return -ENXIO;
/* Master must not be started yet */
if (isdn_net_device_started(n))
return NULL;
return (isdn_net_new(newname, &(n->dev)));
}
return NULL;
if (isdn_net_device_started(m))
return -EBUSY;
return isdn_net_new(p+1, &m->dev);
}
/*
......@@ -2717,7 +2648,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
ulong flags;
#endif
if (p) {
isdn_net_local *lp = p->local;
isdn_net_local *lp = &p->local;
/* See if any registered driver supports the features we want */
features = ((1 << cfg->l2_proto) << ISDN_FEATURE_L2_SHIFT) |
......@@ -2777,7 +2708,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
case ISDN_NET_ENCAP_X25IFACE:
#ifndef CONFIG_ISDN_X25
printk(KERN_WARNING "%s: isdn-x25 support not configured\n",
p->local->name);
p->local.name);
return -EINVAL;
#else
p->dev.type = ARPHRD_X25; /* change ARP type */
......@@ -2793,7 +2724,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
break;
printk(KERN_WARNING
"%s: encapsulation protocol %d not supported\n",
p->local->name, cfg->p_encap);
p->local.name, cfg->p_encap);
return -EINVAL;
}
if (strlen(cfg->drvid)) {
......@@ -2830,7 +2761,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
/* If binding is exclusive, try to grab the channel */
save_flags(flags);
if ((i = isdn_get_free_channel(ISDN_USAGE_NET,
if ((i = isdn_get_free_slot(ISDN_USAGE_NET,
lp->l2_proto, lp->l3_proto, drvidx,
chidx, lp->msn)) < 0) {
/* Grab failed, because desired channel is in use */
......@@ -2839,8 +2770,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
return -EBUSY;
}
/* All went ok, so update isdninfo */
dev->usage[i] = ISDN_USAGE_EXCLUSIVE;
isdn_info_update();
isdn_slot_set_usage(i, ISDN_USAGE_EXCLUSIVE);
restore_flags(flags);
lp->exclusive = i;
} else {
......@@ -2860,7 +2790,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
lp->charge = cfg->charge;
lp->l2_proto = cfg->l2_proto;
lp->l3_proto = cfg->l3_proto;
lp->cbdelay = cfg->cbdelay;
lp->cbdelay = cfg->cbdelay * HZ / 5;
lp->dialmax = cfg->dialmax;
lp->triggercps = cfg->triggercps;
lp->slavedelay = cfg->slavedelay * HZ;
......@@ -2944,7 +2874,7 @@ isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
isdn_net_dev *p = isdn_net_findif(cfg->name);
if (p) {
isdn_net_local *lp = p->local;
isdn_net_local *lp = &p->local;
strcpy(cfg->eaz, lp->msn);
cfg->exclusive = lp->exclusive;
......@@ -2968,7 +2898,7 @@ isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
cfg->dialmode = lp->flags & ISDN_NET_DIALMODE_MASK;
cfg->chargehup = (lp->hupflags & 4) ? 1 : 0;
cfg->ihup = (lp->hupflags & 8) ? 1 : 0;
cfg->cbdelay = lp->cbdelay;
cfg->cbdelay = lp->cbdelay * 5 / HZ;
cfg->dialmax = lp->dialmax;
cfg->triggercps = lp->triggercps;
cfg->slavedelay = lp->slavedelay / HZ;
......@@ -3003,8 +2933,8 @@ isdn_net_addphone(isdn_net_ioctl_phone * phone)
if (!(n = (isdn_net_phone *) kmalloc(sizeof(isdn_net_phone), GFP_KERNEL)))
return -ENOMEM;
strcpy(n->num, phone->phone);
n->next = p->local->phone[phone->outgoing & 1];
p->local->phone[phone->outgoing & 1] = n;
n->next = p->local.phone[phone->outgoing & 1];
p->local.phone[phone->outgoing & 1] = n;
return 0;
}
return -ENODEV;
......@@ -3026,7 +2956,7 @@ isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones)
if (!p)
return -ENODEV;
inout &= 1;
for (n = p->local->phone[inout]; n; n = n->next) {
for (n = p->local.phone[inout]; n; n = n->next) {
if (more) {
put_user(' ', phones++);
count++;
......@@ -3051,7 +2981,7 @@ int
isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone *peer)
{
isdn_net_dev *p = isdn_net_findif(phone->name);
int ch, dv, idx;
int idx;
if (!p) return -ENODEV;
/*
......@@ -3060,15 +2990,12 @@ isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone *peer)
* in (partially) wrong number copied to user. This race
* currently ignored.
*/
ch = p->local->isdn_channel;
dv = p->local->isdn_device;
if(ch<0 && dv<0) return -ENOTCONN;
idx = isdn_dc2minor(dv, ch);
if (idx<0) return -ENODEV;
idx = p->local.isdn_slot;
if (idx<0) return -ENOTCONN;
/* for pre-bound channels, we need this extra check */
if ( strncmp(dev->num[idx],"???",3) == 0 ) return -ENOTCONN;
strncpy(phone->phone,dev->num[idx],ISDN_MSNLEN);
phone->outgoing=USG_OUTGOING(dev->usage[idx]);
if (strncmp(isdn_slot_num(idx),"???",3) == 0 ) return -ENOTCONN;
strncpy(phone->phone,isdn_slot_num(idx),ISDN_MSNLEN);
phone->outgoing=USG_OUTGOING(isdn_slot_usage(idx));
if ( copy_to_user(peer,phone,sizeof(*peer)) ) return -EFAULT;
return 0;
}
......@@ -3087,16 +3014,16 @@ isdn_net_delphone(isdn_net_ioctl_phone * phone)
if (p) {
save_flags(flags);
cli();
n = p->local->phone[inout];
n = p->local.phone[inout];
m = NULL;
while (n) {
if (!strcmp(n->num, phone->phone)) {
if (p->local->dial == n)
p->local->dial = n->next;
if (p->local.dial == n)
p->local.dial = n->next;
if (m)
m->next = n->next;
else
p->local->phone[inout] = n->next;
p->local.phone[inout] = n->next;
kfree(n);
restore_flags(flags);
return 0;
......@@ -3124,15 +3051,15 @@ isdn_net_rmallphone(isdn_net_dev * p)
save_flags(flags);
cli();
for (i = 0; i < 2; i++) {
n = p->local->phone[i];
n = p->local.phone[i];
while (n) {
m = n->next;
kfree(n);
n = m;
}
p->local->phone[i] = NULL;
p->local.phone[i] = NULL;
}
p->local->dial = NULL;
p->local.dial = NULL;
restore_flags(flags);
return 0;
}
......@@ -3147,9 +3074,9 @@ isdn_net_force_hangup(char *name)
struct net_device *q;
if (p) {
if (p->local->isdn_device < 0)
if (p->local.isdn_slot < 0)
return 1;
q = p->local->slave;
q = p->local.slave;
/* If this interface has slaves, do a hangup for them also. */
while (q) {
isdn_net_hangup(q);
......@@ -3165,7 +3092,7 @@ isdn_net_force_hangup(char *name)
* Helper-function for isdn_net_rm: Do the real work.
*/
static int
isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
isdn_net_realrm(isdn_net_dev *p)
{
unsigned long flags;
......@@ -3182,42 +3109,37 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
/* Free all phone-entries */
isdn_net_rmallphone(p);
/* If interface is bound exclusive, free channel-usage */
if (p->local->exclusive != -1)
isdn_unexclusive_channel(p->local->pre_device, p->local->pre_channel);
if (p->local->master) {
if (p->local.exclusive != -1)
isdn_unexclusive_channel(p->local.pre_device, p->local.pre_channel);
if (p->local.master) {
/* It's a slave-device, so update master's slave-pointer if necessary */
if (((isdn_net_local *) (p->local->master->priv))->slave == &p->dev)
((isdn_net_local *) (p->local->master->priv))->slave = p->local->slave;
if (((isdn_net_local *) (p->local.master->priv))->slave == &p->dev)
((isdn_net_local *) (p->local.master->priv))->slave = p->local.slave;
} else {
/* Unregister only if it's a master-device */
p->dev.hard_header_cache = p->local->org_hhc;
p->dev.header_cache_update = p->local->org_hcu;
p->dev.hard_header_cache = p->local.org_hhc;
p->dev.header_cache_update = p->local.org_hcu;
unregister_netdev(&p->dev);
}
/* Unlink device from chain */
if (q)
q->next = p->next;
else
dev->netdev = p->next;
if (p->local->slave) {
list_del(&p->global_list);
if (p->local.slave) {
/* If this interface has a slave, remove it also */
char *slavename = ((isdn_net_local *) (p->local->slave->priv))->name;
isdn_net_dev *n = dev->netdev;
q = NULL;
while (n) {
if (!strcmp(n->local->name, slavename)) {
isdn_net_realrm(n, q);
char *slavename = ((isdn_net_local *) (p->local.slave->priv))->name;
struct list_head *l;
list_for_each(l, &isdn_net_devs) {
isdn_net_dev *n = list_entry(l, isdn_net_dev, global_list);
if (!strcmp(n->local.name, slavename)) {
isdn_net_realrm(n);
break;
}
q = n;
n = (isdn_net_dev *) n->next;
}
}
/* If no more net-devices remain, disable auto-hangup timer */
if (dev->netdev == NULL)
if (list_empty(&isdn_net_devs))
isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0);
restore_flags(flags);
kfree(p->local);
kfree(p);
return 0;
......@@ -3229,21 +3151,14 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
int
isdn_net_rm(char *name)
{
isdn_net_dev *p;
isdn_net_dev *q;
struct list_head *l;
/* Search name in netdev-chain */
p = dev->netdev;
q = NULL;
while (p) {
if (!strcmp(p->local->name, name))
return (isdn_net_realrm(p, q));
q = p;
p = (isdn_net_dev *) p->next;
list_for_each(l, &isdn_net_devs) {
isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
if (!strcmp(p->local.name, name))
return isdn_net_realrm(p);
}
/* If no more net-devices remain, disable auto-hangup timer */
if (dev->netdev == NULL)
isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0);
return -ENODEV;
}
......@@ -3259,16 +3174,17 @@ isdn_net_rmall(void)
/* Walk through netdev-chain */
save_flags(flags);
cli();
while (dev->netdev) {
if (!dev->netdev->local->master) {
while (!list_empty(&isdn_net_devs)) {
isdn_net_dev *p = list_entry(isdn_net_devs.next, isdn_net_dev, global_list);
/* Remove master-devices only, slaves get removed with their master */
if ((ret = isdn_net_realrm(dev->netdev, NULL))) {
if (!p->local.master) {
if ((ret = isdn_net_realrm(p))) {
restore_flags(flags);
return ret;
}
}
}
dev->netdev = NULL;
restore_flags(flags);
return 0;
}
......@@ -31,8 +31,8 @@
#define CISCO_SLARP_REPLY 1
#define CISCO_SLARP_KEEPALIVE 2
extern char *isdn_net_new(char *, struct net_device *);
extern char *isdn_net_newslave(char *);
extern int isdn_net_new(char *, struct net_device *);
extern int isdn_net_newslave(char *);
extern int isdn_net_rm(char *);
extern int isdn_net_rmall(void);
extern int isdn_net_stat_callback(int, isdn_ctrl *);
......@@ -44,7 +44,6 @@ extern int isdn_net_getpeer(isdn_net_ioctl_phone *, isdn_net_ioctl_phone *);
extern int isdn_net_delphone(isdn_net_ioctl_phone *);
extern int isdn_net_find_icall(int, int, int, setup_parm *);
extern void isdn_net_hangup(struct net_device *);
extern void isdn_net_dial(void);
extern void isdn_net_autohup(void);
extern int isdn_net_force_hangup(char *);
extern int isdn_net_force_dial(char *);
......@@ -131,7 +130,7 @@ static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp)
if (master_lp->netdev->queue == lp) {
master_lp->netdev->queue = lp->next;
if (lp->next == lp) { /* last in queue */
master_lp->netdev->queue = master_lp->netdev->local;
master_lp->netdev->queue = &master_lp->netdev->local;
}
}
lp->next = lp->last = lp; /* (re)set own pointers */
......
......@@ -165,14 +165,15 @@ isdn_ppp_bind(isdn_net_local * lp)
save_flags(flags);
cli();
if (lp->pppbind < 0) { /* device bounded to ippp device ? */
isdn_net_dev *net_dev = dev->netdev;
struct list_head *l;
char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */
memset(exclusive, 0, ISDN_MAX_CHANNELS);
while (net_dev) { /* step through net devices to find exclusive minors */
isdn_net_local *lp = net_dev->local;
/* step through net devices to find exclusive minors */
list_for_each(l, &isdn_net_devs) {
isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
isdn_net_local *lp = &p->local;
if (lp->pppbind >= 0)
exclusive[lp->pppbind] = 1;
net_dev = net_dev->next;
}
/*
* search a free device / slot
......@@ -804,11 +805,11 @@ isdn_ppp_write(struct file *file, const char *buf, size_t count, loff_t *off)
if (proto != PPP_LCP)
lp->huptimer = 0;
if (lp->isdn_device < 0 || lp->isdn_channel < 0) {
if (lp->isdn_slot < 0) {
retval = 0;
goto out;
}
if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) &&
if ((dev->drv[isdn_slot_driver(lp->isdn_slot)]->flags & DRV_FLAG_RUNNING) &&
lp->dialstate == 0 &&
(lp->flags & ISDN_NET_CONNECTED)) {
unsigned short hl;
......@@ -818,7 +819,7 @@ isdn_ppp_write(struct file *file, const char *buf, size_t count, loff_t *off)
* sk_buff. old call to dev_alloc_skb only reserved
* 16 bytes, now we are looking what the driver want
*/
hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
hl = isdn_slot_hdrlen(lp->isdn_slot);
skb = alloc_skb(hl+count, GFP_ATOMIC);
if (!skb) {
printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
......@@ -974,7 +975,7 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
int slot;
int proto;
if (net_dev->local->master)
if (net_dev->local.master)
BUG(); // we're called with the master device always
slot = lp->ppp_slot;
......@@ -1077,12 +1078,12 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
case PPP_VJC_UNCOMP:
if (is->debug & 0x20)
printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
if (net_dev->local->ppp_slot < 0) {
if (net_dev->local.ppp_slot < 0) {
printk(KERN_ERR __FUNCTION__": net_dev->local->ppp_slot(%d) out of range\n",
net_dev->local->ppp_slot);
net_dev->local.ppp_slot);
goto drop_packet;
}
if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
if (slhc_remember(ippp_table[net_dev->local.ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
goto drop_packet;
}
......@@ -1103,12 +1104,12 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
}
skb_put(skb, skb_old->len + 128);
memcpy(skb->data, skb_old->data, skb_old->len);
if (net_dev->local->ppp_slot < 0) {
if (net_dev->local.ppp_slot < 0) {
printk(KERN_ERR __FUNCTION__": net_dev->local->ppp_slot(%d) out of range\n",
net_dev->local->ppp_slot);
net_dev->local.ppp_slot);
goto drop_packet;
}
pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_slot]->slcomp,
skb->data, skb_old->len);
kfree_skb(skb_old);
if (pkt_len < 0)
......@@ -1144,7 +1145,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
return;
drop_packet:
net_dev->local->stats.rx_dropped++;
net_dev->local.stats.rx_dropped++;
kfree_skb(skb);
}
......@@ -1263,7 +1264,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
* sk_buff. old call to dev_alloc_skb only reserved
* 16 bytes, now we are looking what the driver want.
*/
hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen + IPPP_MAX_HEADER;
hl = isdn_slot_hdrlen(lp->isdn_slot) + IPPP_MAX_HEADER;;
/*
* Note: hl might still be insufficient because the method
* above does not account for a possibible MPPP slave channel
......@@ -1976,7 +1977,7 @@ isdn_ppp_dial_slave(char *name)
if (!(ndev = isdn_net_findif(name)))
return 1;
lp = ndev->local;
lp = &ndev->local;
if (!(lp->flags & ISDN_NET_CONNECTED))
return 5;
......@@ -2007,7 +2008,7 @@ isdn_ppp_hangup_slave(char *name)
if (!(ndev = isdn_net_findif(name)))
return 1;
lp = ndev->local;
lp = &ndev->local;
if (!(lp->flags & ISDN_NET_CONNECTED))
return 5;
......@@ -2094,7 +2095,7 @@ static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
isdn_net_local *lp = is->lp;
/* Alloc large enough skb */
hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
hl = isdn_slot_hdrlen(lp->isdn_slot);
skb = alloc_skb(len + hl + 16,GFP_ATOMIC);
if(!skb) {
printk(KERN_WARNING
......
......@@ -128,7 +128,7 @@ isdn_tty_readmodem(void)
modem_info *info;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
if ((midx = dev->m_idx[i]) >= 0) {
if ((midx = isdn_slot_m_idx(i)) >= 0) {
info = &dev->mdm.info[midx];
if (info->online) {
r = 0;
......@@ -143,9 +143,9 @@ isdn_tty_readmodem(void)
if (c > 0) {
save_flags(flags);
cli();
r = isdn_readbchan(info->isdn_driver, info->isdn_channel,
r = isdn_slot_readbchan(info->isdn_slot,
tty->flip.char_buf_ptr,
tty->flip.flag_buf_ptr, c, 0);
tty->flip.flag_buf_ptr, c);
/* CISCO AsyncPPP Hack */
if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
memset(tty->flip.flag_buf_ptr, 0, r);
......@@ -182,7 +182,7 @@ isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
#endif
modem_info *info;
if ((midx = dev->m_idx[i]) < 0) {
if ((midx = isdn_slot_m_idx(i)) < 0) {
/* if midx is invalid, packet is not for tty */
return 0;
}
......@@ -315,8 +315,7 @@ isdn_tty_tint(modem_info * info)
if (!skb)
return;
len = skb->len;
if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,
info->isdn_channel, 1, skb)) == len) {
if ((slen = isdn_slot_write(info->isdn_slot, skb)) == len) {
struct tty_struct *tty = info->tty;
info->send_outstanding++;
info->msr &= ~UART_MSR_CTS;
......@@ -479,11 +478,11 @@ isdn_tty_senddown(modem_info * info)
atomic_inc(&info->xmit_lock);
if (!(atomic_dec_and_test(&info->xmit_lock)))
return;
if (info->isdn_driver < 0) {
if (info->isdn_slot < 0) {
info->xmit_count = 0;
return;
}
skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4;
skb_res = isdn_slot_hdrlen(info->isdn_slot);
#ifdef CONFIG_ISDN_AUDIO
if (info->vonline & 2)
audio_len = buflen * voice_cf[info->emu.vpar[3]];
......@@ -627,7 +626,6 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m)
int usg = ISDN_USAGE_MODEM;
int si = 7;
int l2 = m->mdmreg[REG_L2PROT];
isdn_ctrl cmd;
ulong flags;
int i;
int j;
......@@ -652,56 +650,34 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m)
m->mdmreg[REG_SI1I] = si2bit[si];
save_flags(flags);
cli();
i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
i = isdn_get_free_slot(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
if (i < 0) {
restore_flags(flags);
isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
} else {
info->isdn_driver = dev->drvmap[i];
info->isdn_channel = dev->chanmap[i];
info->drv_index = i;
dev->m_idx[i] = info->line;
dev->usage[i] |= ISDN_USAGE_OUTGOING;
struct dial_info dial = {
.l2_proto = l2,
.l3_proto = m->mdmreg[REG_L3PROT],
.si1 = si,
.si2 = m->mdmreg[REG_SI2],
.msn = m->msn,
.phone = n,
};
info->isdn_slot = i;
isdn_slot_set_m_idx(i, info->line);
info->last_dir = 1;
info->last_l2 = l2;
strcpy(info->last_num, n);
isdn_info_update();
restore_flags(flags);
cmd.driver = info->isdn_driver;
cmd.arg = info->isdn_channel;
cmd.command = ISDN_CMD_CLREAZ;
isdn_command(&cmd);
strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
cmd.driver = info->isdn_driver;
cmd.command = ISDN_CMD_SETEAZ;
isdn_command(&cmd);
cmd.driver = info->isdn_driver;
cmd.command = ISDN_CMD_SETL2;
info->last_l2 = l2;
cmd.arg = info->isdn_channel + (l2 << 8);
isdn_command(&cmd);
cmd.driver = info->isdn_driver;
cmd.command = ISDN_CMD_SETL3;
cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
#ifdef CONFIG_ISDN_TTY_FAX
if (l2 == ISDN_PROTO_L2_FAX) {
cmd.parm.fax = info->fax;
dial.fax = info->fax;
info->fax->direction = ISDN_TTY_FAX_CONN_OUT;
}
#endif
isdn_command(&cmd);
cmd.driver = info->isdn_driver;
cmd.arg = info->isdn_channel;
sprintf(cmd.parm.setup.phone, "%s", n);
sprintf(cmd.parm.setup.eazmsn, "%s",
isdn_map_eaz2msn(m->msn, info->isdn_driver));
cmd.parm.setup.si1 = si;
cmd.parm.setup.si2 = m->mdmreg[REG_SI2];
cmd.command = ISDN_CMD_DIAL;
info->dialing = 1;
info->emu.carrierwait = 0;
strcpy(dev->num[i], n);
isdn_info_update();
isdn_command(&cmd);
isdn_slot_dial(info->isdn_slot, &dial);
isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
}
}
......@@ -714,19 +690,15 @@ void
isdn_tty_modem_hup(modem_info * info, int local)
{
isdn_ctrl cmd;
int di, ch;
int slot;
if (!info)
return;
di = info->isdn_driver;
ch = info->isdn_channel;
if (di < 0 || ch < 0)
slot = info->isdn_slot;
if (slot < 0)
return;
info->isdn_driver = -1;
info->isdn_channel = -1;
#ifdef ISDN_DEBUG_MODEM_HUP
printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);
#endif
......@@ -768,21 +740,14 @@ isdn_tty_modem_hup(modem_info * info, int local)
info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
info->lsr |= UART_LSR_TEMT;
if (local) {
cmd.driver = di;
cmd.command = ISDN_CMD_HANGUP;
cmd.arg = ch;
isdn_command(&cmd);
}
if (local)
isdn_slot_command(slot, ISDN_CMD_HANGUP, &cmd);
isdn_all_eaz(di, ch);
isdn_slot_all_eaz(slot);
info->emu.mdmreg[REG_RINGCNT] = 0;
isdn_free_channel(di, ch, 0);
if (info->drv_index >= 0) {
dev->m_idx[info->drv_index] = -1;
info->drv_index = -1;
}
isdn_slot_free(slot, 0);
isdn_slot_set_m_idx(slot, -1);
info->isdn_slot = -1;
}
/*
......@@ -812,11 +777,11 @@ isdn_tty_suspend(char *id, modem_info * info, atemu * m)
printk(KERN_DEBUG "Msusp ttyI%d\n", info->line);
#endif
l = strlen(id);
if ((info->isdn_driver >= 0)) {
if ((info->isdn_slot >= 0)) {
cmd.parm.cmsg.Length = l+18;
cmd.parm.cmsg.Command = CAPI_FACILITY;
cmd.parm.cmsg.Subcommand = CAPI_REQ;
cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
cmd.parm.cmsg.adr.Controller = isdn_slot_driver(info->isdn_slot) + 1;
cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */
cmd.parm.cmsg.para[1] = 0;
cmd.parm.cmsg.para[2] = l + 3;
......@@ -824,10 +789,7 @@ isdn_tty_suspend(char *id, modem_info * info, atemu * m)
cmd.parm.cmsg.para[4] = 0;
cmd.parm.cmsg.para[5] = l;
strncpy(&cmd.parm.cmsg.para[6], id, l);
cmd.command = CAPI_PUT_MESSAGE;
cmd.driver = info->isdn_driver;
cmd.arg = info->isdn_channel;
isdn_command(&cmd);
isdn_slot_command(info->isdn_slot, CAPI_PUT_MESSAGE, &cmd);
}
}
......@@ -871,43 +833,26 @@ isdn_tty_resume(char *id, modem_info * info, atemu * m)
m->mdmreg[REG_SI1I] = si2bit[si];
save_flags(flags);
cli();
i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
i = isdn_get_free_slot(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
if (i < 0) {
restore_flags(flags);
isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
} else {
info->isdn_driver = dev->drvmap[i];
info->isdn_channel = dev->chanmap[i];
info->drv_index = i;
dev->m_idx[i] = info->line;
dev->usage[i] |= ISDN_USAGE_OUTGOING;
info->isdn_slot = i;
isdn_slot_set_m_idx(i, info->line);
isdn_slot_set_usage(i, isdn_slot_usage(i) | ISDN_USAGE_OUTGOING);
info->last_dir = 1;
// strcpy(info->last_num, n);
isdn_info_update();
restore_flags(flags);
cmd.driver = info->isdn_driver;
cmd.arg = info->isdn_channel;
cmd.command = ISDN_CMD_CLREAZ;
isdn_command(&cmd);
strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
cmd.driver = info->isdn_driver;
cmd.command = ISDN_CMD_SETEAZ;
isdn_command(&cmd);
cmd.driver = info->isdn_driver;
cmd.command = ISDN_CMD_SETL2;
info->last_l2 = l2;
cmd.arg = info->isdn_channel + (l2 << 8);
isdn_command(&cmd);
cmd.driver = info->isdn_driver;
cmd.command = ISDN_CMD_SETL3;
cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
isdn_command(&cmd);
cmd.driver = info->isdn_driver;
cmd.arg = info->isdn_channel;
cmd.arg = l2 << 8;
isdn_slot_command(info->isdn_slot, ISDN_CMD_SETL2, &cmd);
cmd.arg = m->mdmreg[REG_L3PROT] << 8;
isdn_slot_command(info->isdn_slot, ISDN_CMD_SETL3, &cmd);
cmd.parm.cmsg.Length = l+18;
cmd.parm.cmsg.Command = CAPI_FACILITY;
cmd.parm.cmsg.Subcommand = CAPI_REQ;
cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
cmd.parm.cmsg.adr.Controller = isdn_slot_driver(info->isdn_slot) + 1;
cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */
cmd.parm.cmsg.para[1] = 0;
cmd.parm.cmsg.para[2] = l+3;
......@@ -915,11 +860,10 @@ isdn_tty_resume(char *id, modem_info * info, atemu * m)
cmd.parm.cmsg.para[4] = 0;
cmd.parm.cmsg.para[5] = l;
strncpy(&cmd.parm.cmsg.para[6], id, l);
cmd.command =CAPI_PUT_MESSAGE;
info->dialing = 1;
// strcpy(dev->num[i], n);
isdn_info_update();
isdn_command(&cmd);
isdn_slot_command(info->isdn_slot, CAPI_PUT_MESSAGE, &cmd);
isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
}
}
......@@ -965,51 +909,33 @@ isdn_tty_send_msg(modem_info * info, atemu * m, char *msg)
m->mdmreg[REG_SI1I] = si2bit[si];
save_flags(flags);
cli();
i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
i = isdn_get_free_slot(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
if (i < 0) {
restore_flags(flags);
isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
} else {
info->isdn_driver = dev->drvmap[i];
info->isdn_channel = dev->chanmap[i];
info->drv_index = i;
dev->m_idx[i] = info->line;
dev->usage[i] |= ISDN_USAGE_OUTGOING;
info->isdn_slot = i;
isdn_slot_set_m_idx(i, info->line);
isdn_slot_set_usage(i, isdn_slot_usage(i) | ISDN_USAGE_OUTGOING);
info->last_dir = 1;
isdn_info_update();
restore_flags(flags);
cmd.driver = info->isdn_driver;
cmd.arg = info->isdn_channel;
cmd.command = ISDN_CMD_CLREAZ;
isdn_command(&cmd);
strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
cmd.driver = info->isdn_driver;
cmd.command = ISDN_CMD_SETEAZ;
isdn_command(&cmd);
cmd.driver = info->isdn_driver;
cmd.command = ISDN_CMD_SETL2;
info->last_l2 = l2;
cmd.arg = info->isdn_channel + (l2 << 8);
isdn_command(&cmd);
cmd.driver = info->isdn_driver;
cmd.command = ISDN_CMD_SETL3;
cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
isdn_command(&cmd);
cmd.driver = info->isdn_driver;
cmd.arg = info->isdn_channel;
cmd.arg = l2 << 8;
isdn_slot_command(info->isdn_slot, ISDN_CMD_SETL2, &cmd);
cmd.arg = m->mdmreg[REG_L3PROT] << 8;
isdn_slot_command(info->isdn_slot, ISDN_CMD_SETL3, &cmd);
cmd.parm.cmsg.Length = l+14;
cmd.parm.cmsg.Command = CAPI_MANUFACTURER;
cmd.parm.cmsg.Subcommand = CAPI_REQ;
cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
cmd.parm.cmsg.adr.Controller = isdn_slot_driver(info->isdn_slot) + 1;
cmd.parm.cmsg.para[0] = l+1;
strncpy(&cmd.parm.cmsg.para[1], msg, l);
cmd.parm.cmsg.para[l+1] = 0xd;
cmd.command =CAPI_PUT_MESSAGE;
/* info->dialing = 1;
strcpy(dev->num[i], n);
isdn_info_update();
*/
isdn_command(&cmd);
isdn_slot_command(info->isdn_slot, CAPI_PUT_MESSAGE, &cmd);
}
}
......@@ -1173,6 +1099,7 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co
{
int c;
int total = 0;
int di;
modem_info *info = (modem_info *) tty->driver_data;
atemu *m = &info->emu;
......@@ -1186,8 +1113,9 @@ 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;
if (info->isdn_driver >= 0 && c > dev->drv[info->isdn_driver]->maxbufsize)
c = dev->drv[info->isdn_driver]->maxbufsize;
di = isdn_slot_driver(info->isdn_slot);
if (di >= 0 && c > dev->drv[di]->maxbufsize)
c = dev->drv[di]->maxbufsize;
if (c <= 0)
break;
if ((info->online > 1)
......@@ -1247,12 +1175,9 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co
if (info->vonline & 4) { /* ETX seen */
isdn_ctrl c;
c.command = ISDN_CMD_FAXCMD;
c.driver = info->isdn_driver;
c.arg = info->isdn_channel;
c.parm.aux.cmd = ISDN_FAX_CLASS1_CTRL;
c.parm.aux.subcmd = ETX;
isdn_command(&c);
isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &c);
}
info->vonline = 0;
#ifdef ISDN_DEBUG_MODEM_VOICE
......@@ -2015,10 +1940,10 @@ modem_write_profile(atemu * m)
}
int
isdn_tty_modem_init(void)
isdn_tty_init(void)
{
modem *m;
int i;
int i, retval;
modem_info *info;
m = &dev->mdm;
......@@ -2063,13 +1988,15 @@ isdn_tty_modem_init(void)
m->tty_modem.minor_start = 0;
m->cua_modem.subtype = ISDN_SERIAL_TYPE_CALLOUT;
if (tty_register_driver(&m->tty_modem)) {
retval = tty_register_driver(&m->tty_modem);
if (retval) {
printk(KERN_WARNING "isdn_tty: Couldn't register modem-device\n");
return -1;
goto err;
}
if (tty_register_driver(&m->cua_modem)) {
retval = tty_register_driver(&m->cua_modem);
if (retval) {
printk(KERN_WARNING "isdn_tty: Couldn't register modem-callout-device\n");
return -2;
goto err_unregister_tty;
}
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
info = &m->info[i];
......@@ -2098,24 +2025,58 @@ isdn_tty_modem_init(void)
info->normal_termios = m->tty_modem.init_termios;
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
info->isdn_driver = -1;
info->isdn_channel = -1;
info->drv_index = -1;
info->isdn_slot = -1;
info->xmit_size = ISDN_SERIAL_XMIT_SIZE;
skb_queue_head_init(&info->xmit_queue);
#ifdef CONFIG_ISDN_AUDIO
skb_queue_head_init(&info->dtmf_queue);
#endif
if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5, GFP_KERNEL))) {
info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5, GFP_KERNEL);
if (!info->xmit_buf) {
printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
return -3;
#ifdef CONFIG_ISDN_TTY_FAX
kfree(info->fax);
#endif
goto err_unregister_cua;
}
/* Make room for T.70 header */
info->xmit_buf += 4;
}
return 0;
err_unregister_cua:
for (i--; i >= 0; i--) {
info = &m->info[i];
#ifdef CONFIG_ISDN_TTY_FAX
kfree(info->fax);
#endif
kfree(info->xmit_buf - 4);
}
tty_unregister_driver(&dev->mdm.cua_modem);
err_unregister_tty:
tty_unregister_driver(&dev->mdm.tty_modem);
err:
return retval;
}
void
isdn_tty_exit(void)
{
modem *m = &dev->mdm;
modem_info *info;
int i;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
info = &m->info[i];
isdn_tty_cleanup_xmit(info);
#ifdef CONFIG_ISDN_TTY_FAX
kfree(info->fax);
#endif
kfree(info->xmit_buf - 4);
}
tty_unregister_driver(&dev->mdm.cua_modem);
tty_unregister_driver(&dev->mdm.tty_modem);
}
/*
* isdn_tty_match_icall(char *MSN, atemu *tty_emulator, int dev_idx)
......@@ -2227,26 +2188,21 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
#ifndef FIX_FILE_TRANSFER
(info->flags & ISDN_ASYNC_NORMAL_ACTIVE) &&
#endif
(info->isdn_driver == -1) &&
(info->isdn_channel == -1) &&
(USG_NONE(dev->usage[idx]))) {
(info->isdn_slot == -1) &&
(USG_NONE(isdn_slot_usage(idx)))) {
int matchret;
if ((matchret = isdn_tty_match_icall(eaz, &info->emu, di)) > wret)
wret = matchret;
if (!matchret) { /* EAZ is matching */
info->isdn_driver = di;
info->isdn_channel = ch;
info->drv_index = idx;
dev->m_idx[idx] = info->line;
dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
dev->usage[idx] |= isdn_calc_usage(si1, info->emu.mdmreg[REG_L2PROT]);
strcpy(dev->num[idx], nr);
info->isdn_slot = idx;
isdn_slot_set_m_idx(idx, info->line);
strcpy(isdn_slot_num(idx), nr);
strcpy(info->emu.cpn, eaz);
info->emu.mdmreg[REG_SI1I] = si2bit[si1];
info->emu.mdmreg[REG_PLAN] = setup->plan;
info->emu.mdmreg[REG_SCREEN] = setup->screen;
isdn_info_update();
isdn_slot_set_usage(idx, (isdn_slot_usage(idx) & ISDN_USAGE_EXCLUSIVE) | isdn_calc_usage(si1, info->emu.mdmreg[REG_L2PROT]));
restore_flags(flags);
printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr,
info->line);
......@@ -2276,7 +2232,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
if (i < 0)
return 0;
if ((mi = dev->m_idx[i]) >= 0) {
if ((mi = isdn_slot_m_idx(i)) >= 0) {
info = &dev->mdm.info[mi];
switch (c->command) {
case ISDN_STAT_CINF:
......@@ -2290,8 +2246,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
#ifdef ISDN_TTY_STAT_DEBUG
printk(KERN_DEBUG "tty_STAT_BSENT ttyI%d\n", info->line);
#endif
if ((info->isdn_driver == c->driver) &&
(info->isdn_channel == c->arg)) {
if ((info->isdn_slot == isdn_dc2minor(c->driver, c->arg))) {
info->msr |= UART_MSR_CTS;
if (info->send_outstanding)
if (!(--info->send_outstanding))
......@@ -2375,14 +2330,14 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
info->last_dir = 0;
info->dialing = 0;
info->rcvsched = 1;
if (USG_MODEM(dev->usage[i])) {
if (USG_MODEM(isdn_slot_usage(i))) {
if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) {
strcpy(info->emu.connmsg, c->parm.num);
isdn_tty_modem_result(RESULT_CONNECT, info);
} else
isdn_tty_modem_result(RESULT_CONNECT64000, info);
}
if (USG_VOICE(dev->usage[i]))
if (USG_VOICE(isdn_slot_usage(i)))
isdn_tty_modem_result(RESULT_VCON, info);
return 1;
}
......@@ -2421,7 +2376,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
#endif
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
info = &dev->mdm.info[i];
if (info->isdn_driver == c->driver) {
if (isdn_slot_driver(info->isdn_slot) == c->driver) {
if (info->online)
isdn_tty_modem_hup(info, 1);
}
......@@ -2473,6 +2428,7 @@ isdn_tty_at_cout(char *msg, modem_info * info)
ulong flags;
struct sk_buff *skb = 0;
char *sp = 0;
int di,ch;
if (!msg) {
printk(KERN_WARNING "isdn_tty: Null-Message in isdn_tty_at_cout\n");
......@@ -2488,8 +2444,9 @@ 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->online) && (((tty->flip.count + strlen(msg)) >= TTY_FLIPBUF_SIZE) ||
(!skb_queue_empty(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel])))) {
(!skb_queue_empty(&dev->drv[di]->rpqueue[ch])))) {
skb = alloc_skb(strlen(msg)
#ifdef CONFIG_ISDN_AUDIO
+ sizeof(isdn_audio_skb)
......@@ -2532,8 +2489,8 @@ isdn_tty_at_cout(char *msg, modem_info * info)
}
}
if (skb) {
__skb_queue_tail(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel], skb);
dev->drv[info->isdn_driver]->rcvcount[info->isdn_channel] += skb->len;
__skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
dev->drv[di]->rcvcount[ch] += skb->len;
restore_flags(flags);
/* Schedule dequeuing */
if ((dev->modempoll) && (info->rcvsched))
......@@ -2551,7 +2508,7 @@ isdn_tty_at_cout(char *msg, modem_info * info)
static void
isdn_tty_on_hook(modem_info * info)
{
if (info->isdn_channel >= 0) {
if (info->isdn_slot >= 0) {
#ifdef ISDN_DEBUG_MODEM_HUP
printk(KERN_DEBUG "Mhup in isdn_tty_on_hook\n");
#endif
......@@ -2711,7 +2668,7 @@ isdn_tty_modem_result(int code, modem_info * info)
/* print CID, _before_ _every_ ring */
if (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE)) {
isdn_tty_at_cout("\r\nCALLER NUMBER: ", info);
isdn_tty_at_cout(dev->num[info->drv_index], info);
isdn_tty_at_cout(isdn_slot_num(info->isdn_slot), info);
if (m->mdmreg[REG_CDN] & BIT_CDN) {
isdn_tty_at_cout("\r\nCALLED NUMBER: ", info);
isdn_tty_at_cout(info->emu.cpn, info);
......@@ -2740,7 +2697,7 @@ isdn_tty_modem_result(int code, modem_info * info)
(m->mdmreg[REG_RINGCNT] == 1)) {
isdn_tty_at_cout("\r\n", info);
isdn_tty_at_cout("CALLER NUMBER: ", info);
isdn_tty_at_cout(dev->num[info->drv_index], info);
isdn_tty_at_cout(isdn_slot_num(info->isdn_slot), info);
if (m->mdmreg[REG_CDN] & BIT_CDN) {
isdn_tty_at_cout("\r\nCALLED NUMBER: ", info);
isdn_tty_at_cout(info->emu.cpn, info);
......@@ -3252,7 +3209,7 @@ isdn_tty_cmd_ATA(modem_info * info)
if (info->msr & UART_MSR_RI) {
/* Accept incoming call */
info->last_dir = 0;
strcpy(info->last_num, dev->num[info->drv_index]);
strcpy(info->last_num, isdn_slot_num(info->isdn_slot));
m->mdmreg[REG_RINGCNT] = 0;
info->msr &= ~UART_MSR_RI;
l2 = m->mdmreg[REG_L2PROT];
......@@ -3266,27 +3223,20 @@ isdn_tty_cmd_ATA(modem_info * info)
l2 = ISDN_PROTO_L2_X75I;
}
#endif
cmd.driver = info->isdn_driver;
cmd.command = ISDN_CMD_SETL2;
cmd.arg = info->isdn_channel + (l2 << 8);
cmd.arg = l2 << 8;
info->last_l2 = l2;
isdn_command(&cmd);
cmd.driver = info->isdn_driver;
cmd.command = ISDN_CMD_SETL3;
cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
isdn_slot_command(info->isdn_slot, ISDN_CMD_SETL2, &cmd);
cmd.arg = m->mdmreg[REG_L3PROT] << 8;
#ifdef CONFIG_ISDN_TTY_FAX
if (l2 == ISDN_PROTO_L2_FAX) {
cmd.parm.fax = info->fax;
info->fax->direction = ISDN_TTY_FAX_CONN_IN;
}
#endif
isdn_command(&cmd);
cmd.driver = info->isdn_driver;
cmd.arg = info->isdn_channel;
cmd.command = ISDN_CMD_ACCEPTD;
isdn_slot_command(info->isdn_slot, ISDN_CMD_SETL3, &cmd);
info->dialing = 16;
info->emu.carrierwait = 0;
isdn_command(&cmd);
isdn_slot_command(info->isdn_slot, ISDN_CMD_ACCEPTD, &cmd);
isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
} else
isdn_tty_modem_result(RESULT_NO_ANSWER, info);
......@@ -3642,12 +3592,10 @@ isdn_tty_cmd_PLUSV(char **p, modem_info * info)
PARSE_ERROR1;
m->vpar[4] = par1;
m->vpar[5] = par2;
cmd.driver = info->isdn_driver;
cmd.command = ISDN_CMD_AUDIO;
cmd.arg = info->isdn_channel + (ISDN_AUDIO_SETDD << 8);
cmd.arg = ISDN_AUDIO_SETDD << 8;
cmd.parm.num[0] = par1;
cmd.parm.num[1] = par2;
isdn_command(&cmd);
isdn_slot_command(info->isdn_slot, ISDN_CMD_AUDIO, &cmd);
break;
} else
if (*p[0] == '?') {
......@@ -3973,8 +3921,8 @@ isdn_tty_modem_escape(void)
int midx;
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
if (USG_MODEM(dev->usage[i]))
if ((midx = dev->m_idx[i]) >= 0) {
if (USG_MODEM(isdn_slot_usage(i)))
if ((midx = isdn_slot_m_idx(i)) >= 0) {
modem_info *info = &dev->mdm.info[midx];
if (info->online) {
ton = 1;
......
......@@ -105,7 +105,7 @@ extern void isdn_tty_modem_escape(void);
extern void isdn_tty_modem_ring(void);
extern void isdn_tty_carrier_timeout(void);
extern void isdn_tty_modem_xmit(void);
extern int isdn_tty_modem_init(void);
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 *);
......@@ -119,3 +119,6 @@ extern int isdn_tty_cmd_PLUSF_FAX(char **, modem_info *);
extern int isdn_tty_fax_command(modem_info *, isdn_ctrl *);
extern void isdn_tty_fax_bitorder(modem_info *, struct sk_buff *);
#endif
extern int isdn_tty_init(void);
extern void isdn_tty_exit(void);
......@@ -74,7 +74,7 @@ isdn_tty_fax_modem_result(int code, modem_info * info)
case 2: /* +FCON */
/* Append CPN, if enabled */
if ((m->mdmreg[REG_CPNFCON] & BIT_CPNFCON) &&
(!(dev->usage[info->isdn_channel] & ISDN_USAGE_OUTGOING))) {
(!(isdn_slot_usage(info->isdn_slot) & ISDN_USAGE_OUTGOING))) {
sprintf(rs, "/%s", m->cpn);
isdn_tty_at_cout(rs, info);
}
......@@ -360,12 +360,11 @@ isdn_tty_cmd_FCLASS1(char **p, modem_info * info)
default:
PARSE_ERROR1;
}
c.command = ISDN_CMD_FAXCMD;
#ifdef ISDN_TTY_FAX_CMD_DEBUG
printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 %d/%d/%d)\n",
c.parm.aux.cmd, c.parm.aux.subcmd, c.parm.aux.para[0]);
#endif
if (info->isdn_driver < 0) {
if (info->isdn_slot < 0) {
save_flags(flags);
cli();
if ((c.parm.aux.subcmd == AT_EQ_VALUE) ||
......@@ -374,32 +373,21 @@ isdn_tty_cmd_FCLASS1(char **p, modem_info * info)
PARSE_ERROR1;
}
/* get a temporary connection to the first free fax driver */
i = isdn_get_free_channel(ISDN_USAGE_FAX, ISDN_PROTO_L2_FAX,
i = isdn_get_free_slot(ISDN_USAGE_FAX, ISDN_PROTO_L2_FAX,
ISDN_PROTO_L3_FCLASS1, -1, -1, "00");
if (i < 0) {
restore_flags(flags);
PARSE_ERROR1;
}
info->isdn_driver = dev->drvmap[i];
info->isdn_channel = dev->chanmap[i];
info->drv_index = i;
dev->m_idx[i] = info->line;
c.driver = info->isdn_driver;
c.arg = info->isdn_channel;
isdn_command(&c);
isdn_free_channel(info->isdn_driver, info->isdn_channel,
ISDN_USAGE_FAX);
info->isdn_driver = -1;
info->isdn_channel = -1;
if (info->drv_index >= 0) {
dev->m_idx[info->drv_index] = -1;
info->drv_index = -1;
}
info->isdn_slot = i;
isdn_slot_set_m_idx(i, info->line);
isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &c);
isdn_slot_free(info->isdn_slot, ISDN_USAGE_FAX);
isdn_slot_set_m_idx(i, -1);
info->isdn_slot = -1;
restore_flags(flags);
} else {
c.driver = info->isdn_driver;
c.arg = info->isdn_channel;
isdn_command(&c);
isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &c);
}
return 1;
}
......@@ -800,10 +788,7 @@ isdn_tty_cmd_FCLASS2(char **p, modem_info * info)
printk(KERN_DEBUG "isdn_tty: Fax FDR\n");
#endif
f->code = ISDN_TTY_FAX_DR;
cmd.driver = info->isdn_driver;
cmd.arg = info->isdn_channel;
cmd.command = ISDN_CMD_FAXCMD;
isdn_command(&cmd);
isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &cmd);
if (f->phase == ISDN_FAX_PHASE_B) {
f->phase = ISDN_FAX_PHASE_C;
} else if (f->phase == ISDN_FAX_PHASE_D) {
......@@ -855,10 +840,7 @@ isdn_tty_cmd_FCLASS2(char **p, modem_info * info)
#endif
if ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D)) {
f->code = ISDN_TTY_FAX_DT;
cmd.driver = info->isdn_driver;
cmd.arg = info->isdn_channel;
cmd.command = ISDN_CMD_FAXCMD;
isdn_command(&cmd);
isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &cmd);
if (f->phase == ISDN_FAX_PHASE_D) {
f->phase = ISDN_FAX_PHASE_C;
isdn_tty_fax_modem_result(7, info); /* CONNECT */
......@@ -913,10 +895,7 @@ isdn_tty_cmd_FCLASS2(char **p, modem_info * info)
PARSE_ERROR1;
f->fet = par;
f->code = ISDN_TTY_FAX_ET;
cmd.driver = info->isdn_driver;
cmd.arg = info->isdn_channel;
cmd.command = ISDN_CMD_FAXCMD;
isdn_command(&cmd);
isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &cmd);
#ifdef ISDN_TTY_FAX_STAT_DEBUG
printk(KERN_DEBUG "isdn_tty: Fax FET=%d\n", par);
#endif
......
......@@ -515,14 +515,12 @@ isdn_v110_encode(isdn_v110_stream * v, struct sk_buff *skb)
}
int
isdn_v110_stat_callback(int idx, isdn_ctrl * c)
isdn_v110_stat_callback(struct isdn_v110 *iv110, isdn_ctrl *c)
{
isdn_v110_stream *v = NULL;
int i;
int ret;
if (idx < 0)
return 0;
switch (c->command) {
case ISDN_STAT_BSENT:
/* Keep the send-queue of the driver filled
......@@ -531,9 +529,9 @@ isdn_v110_stat_callback(int idx, isdn_ctrl * c)
* send down an Idle-Frame (or an Sync-Frame, if
* v->SyncInit != 0).
*/
if (!(v = dev->v110[idx]))
if (!(v = iv110->v110))
return 0;
atomic_inc(&dev->v110use[idx]);
atomic_inc(&iv110->v110use);
if (v->skbidle > 0) {
v->skbidle--;
ret = 1;
......@@ -560,38 +558,38 @@ isdn_v110_stat_callback(int idx, isdn_ctrl * c)
} else
break;
}
atomic_dec(&dev->v110use[idx]);
atomic_dec(&iv110->v110use);
return ret;
case ISDN_STAT_DHUP:
case ISDN_STAT_BHUP:
while (1) {
atomic_inc(&dev->v110use[idx]);
if (atomic_dec_and_test(&dev->v110use[idx])) {
isdn_v110_close(dev->v110[idx]);
dev->v110[idx] = NULL;
atomic_inc(&iv110->v110use);
if (atomic_dec_and_test(&iv110->v110use)) {
isdn_v110_close(iv110->v110);
iv110->v110 = NULL;
break;
}
sti();
}
break;
case ISDN_STAT_BCONN:
if (dev->v110emu[idx] && (dev->v110[idx] == NULL)) {
if (iv110->v110emu && (iv110->v110 == NULL)) {
int hdrlen = dev->drv[c->driver]->interface->hl_hdrlen;
int maxsize = dev->drv[c->driver]->interface->maxbufsize;
atomic_inc(&dev->v110use[idx]);
switch (dev->v110emu[idx]) {
atomic_inc(&iv110->v110use);
switch (iv110->v110emu) {
case ISDN_PROTO_L2_V11096:
dev->v110[idx] = isdn_v110_open(V110_9600, hdrlen, maxsize);
iv110->v110 = isdn_v110_open(V110_9600, hdrlen, maxsize);
break;
case ISDN_PROTO_L2_V11019:
dev->v110[idx] = isdn_v110_open(V110_19200, hdrlen, maxsize);
iv110->v110 = isdn_v110_open(V110_19200, hdrlen, maxsize);
break;
case ISDN_PROTO_L2_V11038:
dev->v110[idx] = isdn_v110_open(V110_38400, hdrlen, maxsize);
iv110->v110 = isdn_v110_open(V110_38400, hdrlen, maxsize);
break;
default:;
}
if ((v = dev->v110[idx])) {
if ((v = iv110->v110)) {
while (v->SyncInit) {
struct sk_buff *skb = isdn_v110_sync(v);
if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) {
......@@ -603,8 +601,8 @@ isdn_v110_stat_callback(int idx, isdn_ctrl * c)
v->skbidle++;
}
} else
printk(KERN_WARNING "isdn_v110: Couldn't open stream for chan %d\n", idx);
atomic_dec(&dev->v110use[idx]);
printk(KERN_WARNING "isdn_v110: Couldn't open stream\n");
atomic_dec(&iv110->v110use);
}
break;
default:
......
......@@ -9,8 +9,14 @@
*
*/
#ifndef _isdn_v110_h_
#define _isdn_v110_h_
#ifndef ISDN_V110_H
#define ISDN_V110_H
struct isdn_v110 {
int v110emu; /* V.110 emulator-mode 0=none */
atomic_t v110use; /* Usage-Semaphore for stream */
isdn_v110_stream *v110; /* V.110 private data */
};
/*
* isdn_v110_encode will take raw data and encode it using V.110
......@@ -23,7 +29,7 @@ extern struct sk_buff *isdn_v110_encode(isdn_v110_stream *, struct sk_buff *);
*/
extern struct sk_buff *isdn_v110_decode(isdn_v110_stream *, struct sk_buff *);
extern int isdn_v110_stat_callback(int, isdn_ctrl *);
extern int isdn_v110_stat_callback(struct isdn_v110 *v110, isdn_ctrl *);
extern void isdn_v110_close(isdn_v110_stream * v);
#endif
......@@ -757,6 +757,10 @@ isdnloop_vstphone(isdnloop_card * card, char *phone, int caller)
int i;
static char nphone[30];
if (!card) {
printk("BUG!!!\n");
return "";
}
switch (card->ptype) {
case ISDN_PTYPE_EURO:
if (caller) {
......@@ -775,7 +779,7 @@ isdnloop_vstphone(isdnloop_card * card, char *phone, int caller)
return (&phone[strlen(phone) - 1]);
break;
}
return ("\0");
return "";
}
/*
......@@ -882,7 +886,7 @@ isdnloop_parse_cmd(isdnloop_card * card)
isdnloop_vstphone(card, cmd.parm.setup.eazmsn, 1),
cmd.parm.setup.si1,
cmd.parm.setup.si2,
isdnloop_vstphone(card->rcard[ch],
isdnloop_vstphone(card->rcard[ch - 1],
cmd.parm.setup.phone, 0));
isdnloop_fake(card->rcard[ch - 1], buf, card->rch[ch - 1] + 1);
/* Fall through */
......
......@@ -2,6 +2,36 @@ ToDo:
- Find and fix bugs.
- Enable NFS exporting of NTFS.
2.0.24 - Cleanups.
- Treat BUG_ON() as ASSERT() not VERIFY(), i.e. do not use side effects
inside BUG_ON(). (Adam J. Richter)
- Split logical OR expressions inside BUG_ON() into individual BUG_ON()
calls for improved debugging. (Adam J. Richter)
- Add errors flag to the ntfs volume state, accessed via
NVol{,Set,Clear}Errors(vol).
- Do not allow read-write remounts of read-only volumes with errors.
- Clarify comment for ntfs file operation sendfile which was added by
Christoph Hellwig a while ago (just using generic_file_sendfile())
to say that ntfs ->sendfile is only used for the case where the
source data is on the ntfs partition and the destination is
somewhere else, i.e. nothing we need to concern ourselves with.
- Add generic_file_write() as our ntfs file write operation.
2.0.23 - Major bug fixes (races, deadlocks, non-i386 architectures).
- Massive internal locking changes to mft record locking. Fixes lock
recursion and replaces the mrec_lock read/write semaphore with a
mutex. Also removes the now superfluous mft_count. This fixes several
race conditions and deadlocks, especially in the future write code.
- Fix ntfs over loopback for compressed files by adding an
optimization barrier. (gcc was screwing up otherwise ?)
- Miscellaneous cleanups all over the code and a fix or two in error
handling code paths.
Thanks go to Christoph Hellwig for pointing out the following two:
- Remove now unused function fs/ntfs/malloc.h::vmalloc_nofs().
- Fix ntfs_free() for ia64 and parisc by checking for VMALLOC_END, too.
2.0.22 - Cleanups, mainly to ntfs_readdir(), and use C99 initializers.
- Change fs/ntfs/dir.c::ntfs_reddir() to only read/write ->f_pos once
......
......@@ -5,7 +5,7 @@ obj-$(CONFIG_NTFS_FS) += ntfs.o
ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o \
mst.o namei.o super.o sysctl.o time.o unistr.o upcase.o
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.22\"
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.24\"
ifeq ($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
......
......@@ -106,8 +106,6 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate)
if (!NInoMstProtected(ni)) {
if (likely(page_uptodate && !PageError(page)))
SetPageUptodate(page);
unlock_page(page);
return;
} else {
char *addr;
unsigned int i, recs, nr_err;
......@@ -332,6 +330,8 @@ static int ntfs_read_block(struct page *page)
* for it to be read in before we can do the copy.
*
* Return 0 on success and -errno on error.
*
* WARNING: Do not make this function static! It is used by mft.c!
*/
int ntfs_readpage(struct file *file, struct page *page)
{
......@@ -372,8 +372,8 @@ int ntfs_readpage(struct file *file, struct page *page)
else
base_ni = ni->_INE(base_ntfs_ino);
/* Map, pin and lock the mft record for reading. */
mrec = map_mft_record(READ, base_ni);
/* Map, pin and lock the mft record. */
mrec = map_mft_record(base_ni);
if (unlikely(IS_ERR(mrec))) {
err = PTR_ERR(mrec);
goto err_out;
......@@ -416,7 +416,7 @@ int ntfs_readpage(struct file *file, struct page *page)
put_unm_err_out:
put_attr_search_ctx(ctx);
unm_err_out:
unmap_mft_record(READ, base_ni);
unmap_mft_record(base_ni);
err_out:
unlock_page(page);
return err;
......
......@@ -110,7 +110,8 @@ static inline run_list_element *ntfs_rl_realloc(run_list_element *rl,
static inline BOOL ntfs_are_rl_mergeable(run_list_element *dst,
run_list_element *src)
{
BUG_ON(!dst || !src);
BUG_ON(!dst);
BUG_ON(!src);
if ((dst->lcn < 0) || (src->lcn < 0)) /* Are we merging holes? */
return FALSE;
......@@ -192,7 +193,8 @@ static inline run_list_element *ntfs_rl_append(run_list_element *dst,
BOOL right;
int magic;
BUG_ON(!dst || !src);
BUG_ON(!dst);
BUG_ON(!src);
/* First, check if the right hand end needs merging. */
right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1);
......@@ -258,7 +260,8 @@ static inline run_list_element *ntfs_rl_insert(run_list_element *dst,
BOOL hole = FALSE; /* Following a hole */
int magic;
BUG_ON(!dst || !src);
BUG_ON(!dst);
BUG_ON(!src);
/* disc => Discontinuity between the end of @dst and the start of @src.
* This means we might need to insert a hole.
......@@ -362,7 +365,8 @@ static inline run_list_element *ntfs_rl_replace(run_list_element *dst,
BOOL right;
int magic;
BUG_ON(!dst || !src);
BUG_ON(!dst);
BUG_ON(!src);
/* First, merge the left and right ends, if necessary. */
right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1);
......@@ -423,7 +427,8 @@ static inline run_list_element *ntfs_rl_replace(run_list_element *dst,
static inline run_list_element *ntfs_rl_split(run_list_element *dst, int dsize,
run_list_element *src, int ssize, int loc)
{
BUG_ON(!dst || !src);
BUG_ON(!dst);
BUG_ON(!src);
/* Space required: @dst size + @src size + one new hole. */
dst = ntfs_rl_realloc(dst, dsize, dsize + ssize + 1);
......@@ -948,7 +953,7 @@ int map_run_list(ntfs_inode *ni, VCN vcn)
else
base_ni = ni->_INE(base_ntfs_ino);
mrec = map_mft_record(READ, base_ni);
mrec = map_mft_record(base_ni);
if (IS_ERR(mrec))
return PTR_ERR(mrec);
ctx = get_attr_search_ctx(base_ni, mrec);
......@@ -979,7 +984,7 @@ int map_run_list(ntfs_inode *ni, VCN vcn)
put_attr_search_ctx(ctx);
err_out:
unmap_mft_record(READ, base_ni);
unmap_mft_record(base_ni);
return err;
}
......@@ -1671,7 +1676,7 @@ void reinit_attr_search_ctx(attr_search_context *ctx)
return;
} /* Attribute list. */
if (ctx->ntfs_ino != ctx->base_ntfs_ino)
unmap_mft_record(READ, ctx->ntfs_ino);
unmap_mft_record(ctx->ntfs_ino);
init_attr_search_ctx(ctx, ctx->base_ntfs_ino, ctx->base_mrec);
return;
}
......@@ -1704,7 +1709,7 @@ attr_search_context *get_attr_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec)
void put_attr_search_ctx(attr_search_context *ctx)
{
if (ctx->base_ntfs_ino && ctx->ntfs_ino != ctx->base_ntfs_ino)
unmap_mft_record(READ, ctx->ntfs_ino);
unmap_mft_record(ctx->ntfs_ino);
kmem_cache_free(ntfs_attr_ctx_cache, ctx);
return;
}
......
......@@ -467,7 +467,8 @@ int ntfs_read_compressed_block(struct page *page)
* Bad things happen if we get here for anything that is not an
* unnamed $DATA attribute.
*/
BUG_ON(ni->type != AT_DATA || ni->name_len);
BUG_ON(ni->type != AT_DATA);
BUG_ON(ni->name_len);
pages = kmalloc(nr_pages * sizeof(struct page *), GFP_NOFS);
......@@ -608,8 +609,27 @@ int ntfs_read_compressed_block(struct page *page)
if (buffer_uptodate(tbh))
continue;
wait_on_buffer(tbh);
/*
* We need an optimization barrier here, otherwise we start
* hitting the below fixup code when accessing a loopback
* mounted ntfs partition. This indicates either there is a
* race condition in the loop driver or, more likely, gcc
* overoptimises the code without the barrier and it doesn't
* do the Right Thing(TM).
*/
barrier();
if (unlikely(!buffer_uptodate(tbh))) {
ntfs_warning(vol->sb, "Buffer is unlocked but not "
"uptodate! Unplugging the disk queue "
"and rescheduling.");
get_bh(tbh);
blk_run_queues();
schedule();
put_bh(tbh);
if (unlikely(!buffer_uptodate(tbh)))
goto read_err;
ntfs_warning(vol->sb, "Buffer is now uptodate. Good.");
}
}
/*
......
......@@ -76,7 +76,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
u8 *index_end;
u64 mref;
attr_search_context *ctx;
int err = 0, rc;
int err, rc;
VCN vcn, old_vcn;
struct address_space *ia_mapping;
struct page *page;
......@@ -84,23 +84,24 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
ntfs_name *name = NULL;
/* Get hold of the mft record for the directory. */
m = map_mft_record(READ, dir_ni);
if (IS_ERR(m))
goto map_err_out;
m = map_mft_record(dir_ni);
if (unlikely(IS_ERR(m))) {
ntfs_error(sb, "map_mft_record() failed with error code %ld.",
-PTR_ERR(m));
return ERR_MREF(PTR_ERR(m));
}
ctx = get_attr_search_ctx(dir_ni, m);
if (!ctx) {
if (unlikely(!ctx)) {
err = -ENOMEM;
goto unm_err_out;
goto err_out;
}
/* Find the index root attribute in the mft record. */
if (!lookup_attr(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL, 0,
ctx)) {
ntfs_error(sb, "Index root attribute missing in directory "
"inode 0x%lx.", dir_ni->mft_no);
err = -EIO;
goto put_unm_err_out;
goto err_out;
}
/* Get to the index root value (it's been verified in read_inode). */
ir = (INDEX_ROOT*)((u8*)ctx->attr +
......@@ -154,7 +155,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
GFP_NOFS);
if (!name) {
err = -ENOMEM;
goto put_unm_err_out;
goto err_out;
}
}
name->mref = le64_to_cpu(
......@@ -169,7 +170,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
}
mref = le64_to_cpu(ie->_IIF(indexed_file));
put_attr_search_ctx(ctx);
unmap_mft_record(READ, dir_ni);
unmap_mft_record(dir_ni);
return mref;
}
/*
......@@ -208,7 +209,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
name = kmalloc(name_size, GFP_NOFS);
if (!name) {
err = -ENOMEM;
goto put_unm_err_out;
goto err_out;
}
name->mref = le64_to_cpu(ie->_IIF(indexed_file));
name->type = type;
......@@ -267,12 +268,12 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
if (!(ie->_IEH(flags) & INDEX_ENTRY_NODE)) {
if (name) {
put_attr_search_ctx(ctx);
unmap_mft_record(READ, dir_ni);
unmap_mft_record(dir_ni);
return name->mref;
}
ntfs_debug("Entry not found.");
err = -ENOENT;
goto put_unm_err_out;
goto err_out;
} /* Child node present, descend into it. */
/* Consistency check: Verify that an index allocation exists. */
if (!NInoIndexAllocPresent(dir_ni)) {
......@@ -280,11 +281,19 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"requires one. Directory inode 0x%lx is "
"corrupt or driver bug.", dir_ni->mft_no);
err = -EIO;
goto put_unm_err_out;
goto err_out;
}
/* Get the starting vcn of the index_block holding the child node. */
vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->_IEH(length)) - 8);
ia_mapping = VFS_I(dir_ni)->i_mapping;
/*
* We are done with the index root and the mft record. Release them,
* otherwise we deadlock with ntfs_map_page().
*/
put_attr_search_ctx(ctx);
unmap_mft_record(dir_ni);
m = NULL;
ctx = NULL;
descend_into_child_node:
/*
* Convert vcn to index into the index allocation attribute in units
......@@ -296,7 +305,8 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
if (IS_ERR(page)) {
ntfs_error(sb, "Failed to map directory index page, error %ld.",
-PTR_ERR(page));
goto put_unm_err_out;
err = PTR_ERR(page);
goto err_out;
}
kaddr = (u8*)page_address(page);
fast_descend_into_child_node:
......@@ -308,7 +318,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
"inode 0x%lx or driver bug.", dir_ni->mft_no);
err = -EIO;
goto unm_unm_err_out;
goto unm_err_out;
}
if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
ntfs_error(sb, "Actual VCN (0x%Lx) of index buffer is "
......@@ -318,7 +328,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
(long long)sle64_to_cpu(ia->index_block_vcn),
(long long)vcn, dir_ni->mft_no);
err = -EIO;
goto unm_unm_err_out;
goto unm_err_out;
}
if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
dir_ni->_IDM(index_block_size)) {
......@@ -330,7 +340,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
le32_to_cpu(ia->index.allocated_size) + 0x18,
dir_ni->_IDM(index_block_size));
err = -EIO;
goto unm_unm_err_out;
goto unm_err_out;
}
index_end = (u8*)ia + dir_ni->_IDM(index_block_size);
if (index_end > kaddr + PAGE_CACHE_SIZE) {
......@@ -339,7 +349,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"Cannot access! This is probably a bug in the "
"driver.", (long long)vcn, dir_ni->mft_no);
err = -EIO;
goto unm_unm_err_out;
goto unm_err_out;
}
index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
if (index_end > (u8*)ia + dir_ni->_IDM(index_block_size)) {
......@@ -347,7 +357,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"inode 0x%lx exceeds maximum size.",
(long long)vcn, dir_ni->mft_no);
err = -EIO;
goto unm_unm_err_out;
goto unm_err_out;
}
/* The first index entry. */
ie = (INDEX_ENTRY*)((u8*)&ia->index +
......@@ -367,7 +377,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"directory inode 0x%lx.",
dir_ni->mft_no);
err = -EIO;
goto unm_unm_err_out;
goto unm_err_out;
}
/*
* The last entry cannot contain a name. It can however contain
......@@ -403,7 +413,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
GFP_NOFS);
if (!name) {
err = -ENOMEM;
goto unm_unm_err_out;
goto unm_err_out;
}
}
name->mref = le64_to_cpu(
......@@ -418,8 +428,6 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
}
mref = le64_to_cpu(ie->_IIF(indexed_file));
ntfs_unmap_page(page);
put_attr_search_ctx(ctx);
unmap_mft_record(READ, dir_ni);
return mref;
}
/*
......@@ -459,7 +467,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
name = kmalloc(name_size, GFP_NOFS);
if (!name) {
err = -ENOMEM;
goto put_unm_err_out;
goto unm_err_out;
}
name->mref = le64_to_cpu(ie->_IIF(indexed_file));
name->type = type;
......@@ -519,7 +527,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"a leaf node in directory inode 0x%lx.",
dir_ni->mft_no);
err = -EIO;
goto unm_unm_err_out;
goto unm_err_out;
}
/* Child node present, descend into it. */
old_vcn = vcn;
......@@ -539,7 +547,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
ntfs_error(sb, "Negative child node vcn in directory inode "
"0x%lx.", dir_ni->mft_no);
err = -EIO;
goto unm_unm_err_out;
goto unm_err_out;
}
/*
* No child node present, return -ENOENT, unless we have got a matching
......@@ -548,31 +556,26 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
*/
if (name) {
ntfs_unmap_page(page);
put_attr_search_ctx(ctx);
unmap_mft_record(READ, dir_ni);
return name->mref;
}
ntfs_debug("Entry not found.");
err = -ENOENT;
unm_unm_err_out:
unm_err_out:
ntfs_unmap_page(page);
put_unm_err_out:
err_out:
if (ctx)
put_attr_search_ctx(ctx);
unm_err_out:
unmap_mft_record(READ, dir_ni);
if (m)
unmap_mft_record(dir_ni);
if (name) {
kfree(name);
*res = NULL;
}
return ERR_MREF(err);
map_err_out:
ntfs_error(sb, "map_mft_record(READ) failed with error code %ld.",
-PTR_ERR(m));
return ERR_MREF(PTR_ERR(m));
dir_err_out:
ntfs_error(sb, "Corrupt directory. Aborting lookup.");
err = -EIO;
goto put_unm_err_out;
goto err_out;
}
#if 0
......@@ -614,7 +617,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
u8 *index_end;
u64 mref;
attr_search_context *ctx;
int err = 0, rc;
int err, rc;
IGNORE_CASE_BOOL ic;
VCN vcn, old_vcn;
struct address_space *ia_mapping;
......@@ -622,23 +625,24 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
u8 *kaddr;
/* Get hold of the mft record for the directory. */
m = map_mft_record(READ, dir_ni);
if (IS_ERR(m))
goto map_err_out;
m = map_mft_record(dir_ni);
if (IS_ERR(m)) {
ntfs_error(sb, "map_mft_record() failed with error code %ld.",
-PTR_ERR(m));
return ERR_MREF(PTR_ERR(m));
}
ctx = get_attr_search_ctx(dir_ni, m);
if (!ctx) {
err = -ENOMEM;
goto unm_err_out;
goto err_out;
}
/* Find the index root attribute in the mft record. */
if (!lookup_attr(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL, 0,
ctx)) {
ntfs_error(sb, "Index root attribute missing in directory "
"inode 0x%lx.", dir_ni->mft_no);
err = -EIO;
goto put_unm_err_out;
goto err_out;
}
/* Get to the index root value (it's been verified in read_inode). */
ir = (INDEX_ROOT*)((u8*)ctx->attr +
......@@ -689,7 +693,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
found_it:
mref = le64_to_cpu(ie->_IIF(indexed_file));
put_attr_search_ctx(ctx);
unmap_mft_record(READ, dir_ni);
unmap_mft_record(dir_ni);
return mref;
}
/*
......@@ -737,7 +741,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
if (!(ie->_IEH(flags) & INDEX_ENTRY_NODE)) {
/* No child node, return -ENOENT. */
err = -ENOENT;
goto put_unm_err_out;
goto err_out;
} /* Child node present, descend into it. */
/* Consistency check: Verify that an index allocation exists. */
if (!NInoIndexAllocPresent(dir_ni)) {
......@@ -745,11 +749,19 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"requires one. Directory inode 0x%lx is "
"corrupt or driver bug.", dir_ni->mft_no);
err = -EIO;
goto put_unm_err_out;
goto err_out;
}
/* Get the starting vcn of the index_block holding the child node. */
vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->_IEH(length)) - 8);
ia_mapping = VFS_I(dir_ni)->i_mapping;
/*
* We are done with the index root and the mft record. Release them,
* otherwise we deadlock with ntfs_map_page().
*/
put_attr_search_ctx(ctx);
unmap_mft_record(dir_ni);
m = NULL;
ctx = NULL;
descend_into_child_node:
/*
* Convert vcn to index into the index allocation attribute in units
......@@ -761,7 +773,8 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
if (IS_ERR(page)) {
ntfs_error(sb, "Failed to map directory index page, error %ld.",
-PTR_ERR(page));
goto put_unm_err_out;
err = PTR_ERR(page);
goto err_out;
}
kaddr = (u8*)page_address(page);
fast_descend_into_child_node:
......@@ -773,7 +786,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
"inode 0x%lx or driver bug.", dir_ni->mft_no);
err = -EIO;
goto unm_unm_err_out;
goto unm_err_out;
}
if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
ntfs_error(sb, "Actual VCN (0x%Lx) of index buffer is "
......@@ -783,7 +796,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
(long long)sle64_to_cpu(ia->index_block_vcn),
(long long)vcn, dir_ni->mft_no);
err = -EIO;
goto unm_unm_err_out;
goto unm_err_out;
}
if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
dir_ni->_IDM(index_block_size)) {
......@@ -795,7 +808,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
le32_to_cpu(ia->index.allocated_size) + 0x18,
dir_ni->_IDM(index_block_size));
err = -EIO;
goto unm_unm_err_out;
goto unm_err_out;
}
index_end = (u8*)ia + dir_ni->_IDM(index_block_size);
if (index_end > kaddr + PAGE_CACHE_SIZE) {
......@@ -804,7 +817,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"Cannot access! This is probably a bug in the "
"driver.", (long long)vcn, dir_ni->mft_no);
err = -EIO;
goto unm_unm_err_out;
goto unm_err_out;
}
index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
if (index_end > (u8*)ia + dir_ni->_IDM(index_block_size)) {
......@@ -812,7 +825,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"inode 0x%lx exceeds maximum size.",
(long long)vcn, dir_ni->mft_no);
err = -EIO;
goto unm_unm_err_out;
goto unm_err_out;
}
/* The first index entry. */
ie = (INDEX_ENTRY*)((u8*)&ia->index +
......@@ -832,7 +845,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"directory inode 0x%lx.",
dir_ni->mft_no);
err = -EIO;
goto unm_unm_err_out;
goto unm_err_out;
}
/*
* The last entry cannot contain a name. It can however contain
......@@ -865,8 +878,6 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
found_it2:
mref = le64_to_cpu(ie->_IIF(indexed_file));
ntfs_unmap_page(page);
put_attr_search_ctx(ctx);
unmap_mft_record(READ, dir_ni);
return mref;
}
/*
......@@ -917,7 +928,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"a leaf node in directory inode 0x%lx.",
dir_ni->mft_no);
err = -EIO;
goto unm_unm_err_out;
goto unm_err_out;
}
/* Child node present, descend into it. */
old_vcn = vcn;
......@@ -937,26 +948,23 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
ntfs_error(sb, "Negative child node vcn in directory inode "
"0x%lx.", dir_ni->mft_no);
err = -EIO;
goto unm_unm_err_out;
goto unm_err_out;
}
/* No child node, return -ENOENT. */
ntfs_debug("Entry not found.");
err = -ENOENT;
unm_unm_err_out:
unm_err_out:
ntfs_unmap_page(page);
put_unm_err_out:
err_out:
if (ctx)
put_attr_search_ctx(ctx);
unm_err_out:
unmap_mft_record(READ, dir_ni);
if (m)
unmap_mft_record(dir_ni);
return ERR_MREF(err);
map_err_out:
ntfs_error(sb, "map_mft_record(READ) failed with error code %ld.",
-PTR_ERR(m));
return ERR_MREF(PTR_ERR(m));
dir_err_out:
ntfs_error(sb, "Corrupt directory. Aborting lookup.");
err = -EIO;
goto put_unm_err_out;
goto err_out;
}
#endif
......@@ -1095,22 +1103,8 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
goto done;
fpos++;
}
/* Get hold of the mft record for the directory. */
m = map_mft_record(READ, ndir);
if (unlikely(IS_ERR(m))) {
err = PTR_ERR(m);
m = NULL;
ctx = NULL;
goto err_out;
}
ctx = get_attr_search_ctx(ndir, m);
if (unlikely(!ctx)) {
err = -ENOMEM;
goto err_out;
}
/*
* Allocate a buffer to store the current name being processed
* converted to format determined by current NLS.
......@@ -1124,6 +1118,18 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
/* Are we jumping straight into the index allocation attribute? */
if (fpos >= vol->mft_record_size)
goto skip_index_root;
/* Get hold of the mft record for the directory. */
m = map_mft_record(ndir);
if (unlikely(IS_ERR(m))) {
err = PTR_ERR(m);
m = NULL;
goto err_out;
}
ctx = get_attr_search_ctx(ndir, m);
if (unlikely(!ctx)) {
err = -ENOMEM;
goto err_out;
}
/* Get the offset into the index root attribute. */
ir_pos = (s64)fpos;
/* Find the index root attribute in the mft record. */
......@@ -1162,9 +1168,21 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
/* Submit the name to the filldir callback. */
rc = ntfs_filldir(vol, &fpos, ndir, INDEX_TYPE_ROOT, ir, ie,
name, dirent, filldir);
if (rc)
if (rc) {
put_attr_search_ctx(ctx);
unmap_mft_record(ndir);
goto abort;
}
}
/*
* We are done with the index root and the mft record for that matter.
* We need to release it, otherwise we deadlock on ntfs_attr_iget()
* and/or ntfs_read_page().
*/
put_attr_search_ctx(ctx);
unmap_mft_record(ndir);
m = NULL;
ctx = NULL;
/* If there is no index allocation attribute we are finished. */
if (!NInoIndexAllocPresent(ndir))
goto EOD;
......@@ -1197,7 +1215,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
/* Get the starting bit position in the current bitmap page. */
cur_bmp_pos = bmp_pos & ((PAGE_CACHE_SIZE * 8) - 1);
bmp_pos &= ~((PAGE_CACHE_SIZE * 8) - 1);
bmp_pos &= ~(u64)((PAGE_CACHE_SIZE * 8) - 1);
get_next_bmp_page:
ntfs_debug("Reading bitmap with page index 0x%Lx, bit ofs 0x%Lx",
(long long)bmp_pos >> (3 + PAGE_CACHE_SHIFT),
......@@ -1343,8 +1361,6 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
/* We are finished, set fpos to EOD. */
fpos = vdir->i_size + vol->mft_record_size;
abort:
put_attr_search_ctx(ctx);
unmap_mft_record(READ, ndir);
kfree(name);
done:
#ifdef DEBUG
......@@ -1366,7 +1382,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (ctx)
put_attr_search_ctx(ctx);
if (m)
unmap_mft_record(READ, ndir);
unmap_mft_record(ndir);
if (!err)
err = -EIO;
ntfs_debug("Failed. Returning error code %i.", -err);
......
......@@ -51,8 +51,15 @@ static int ntfs_file_open(struct inode *vi, struct file *filp)
struct file_operations ntfs_file_ops = {
.llseek = generic_file_llseek, /* Seek inside file. */
.read = generic_file_read, /* Read from file. */
#ifdef NTFS_RW
.write = generic_file_write, /* Write to a file. */
#endif
.mmap = generic_file_mmap, /* Mmap file. */
.sendfile = generic_file_sendfile,/* Zero-copy data send. */
.sendfile = generic_file_sendfile,/* Zero-copy data send with the
data source being on the
ntfs partition. We don't
need to care about the data
destination. */
.open = ntfs_file_open, /* Open file. */
};
......
......@@ -278,7 +278,9 @@ void ntfs_destroy_big_inode(struct inode *inode)
ntfs_inode *ni = NTFS_I(inode);
ntfs_debug("Entering.");
BUG_ON(atomic_read(&ni->mft_count) || !atomic_dec_and_test(&ni->count));
BUG_ON(ni->page);
if (!atomic_dec_and_test(&ni->count))
BUG();
kmem_cache_free(ntfs_big_inode_cache, NTFS_I(inode));
}
......@@ -299,7 +301,9 @@ static inline ntfs_inode *ntfs_alloc_extent_inode(void)
void ntfs_destroy_extent_inode(ntfs_inode *ni)
{
ntfs_debug("Entering.");
BUG_ON(atomic_read(&ni->mft_count) || !atomic_dec_and_test(&ni->count));
BUG_ON(ni->page);
if (!atomic_dec_and_test(&ni->count))
BUG();
kmem_cache_free(ntfs_inode_cache, ni);
}
......@@ -323,8 +327,7 @@ static void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni)
atomic_set(&ni->count, 1);
ni->vol = NTFS_SB(sb);
init_run_list(&ni->run_list);
init_rwsem(&ni->mrec_lock);
atomic_set(&ni->mft_count, 0);
init_MUTEX(&ni->mrec_lock);
ni->page = NULL;
ni->page_ofs = 0;
ni->attr_list_size = 0;
......@@ -504,7 +507,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
ntfs_init_big_inode(vi);
ni = NTFS_I(vi);
m = map_mft_record(READ, ni);
m = map_mft_record(ni);
if (IS_ERR(m)) {
err = PTR_ERR(m);
goto err_out;
......@@ -790,6 +793,11 @@ static int ntfs_read_locked_inode(struct inode *vi)
/* No index allocation. */
vi->i_size = ni->initialized_size =
ni->allocated_size = 0;
/* We are done with the mft record, so we release it. */
put_attr_search_ctx(ctx);
unmap_mft_record(ni);
m = NULL;
ctx = NULL;
goto skip_large_dir_stuff;
} /* LARGE_INDEX: Index allocation present. Setup state. */
NInoSetIndexAllocPresent(ni);
......@@ -834,7 +842,14 @@ static int ntfs_read_locked_inode(struct inode *vi)
ctx->attr->_ANR(initialized_size));
ni->allocated_size = sle64_to_cpu(
ctx->attr->_ANR(allocated_size));
/*
* We are done with the mft record, so we release it. Otherwise
*
*/
put_attr_search_ctx(ctx);
unmap_mft_record(ni);
m = NULL;
ctx = NULL;
/* Get the index bitmap attribute inode. */
bvi = ntfs_attr_iget(vi, AT_BITMAP, I30, 4);
if (unlikely(IS_ERR(bvi))) {
......@@ -858,7 +873,6 @@ static int ntfs_read_locked_inode(struct inode *vi)
bvi->i_size << 3, vi->i_size);
goto unm_err_out;
}
skip_large_dir_stuff:
/* Everyone gets read and scan permissions. */
vi->i_mode |= S_IRUGO | S_IXUGO;
......@@ -998,6 +1012,11 @@ static int ntfs_read_locked_inode(struct inode *vi)
le32_to_cpu(ctx->attr->_ARA(value_length));
}
no_data_attr_special_case:
/* We are done with the mft record, so we release it. */
put_attr_search_ctx(ctx);
unmap_mft_record(ni);
m = NULL;
ctx = NULL;
/* Everyone gets all permissions. */
vi->i_mode |= S_IRWXUGO;
/* If read-only, noone gets write permissions. */
......@@ -1026,9 +1045,6 @@ static int ntfs_read_locked_inode(struct inode *vi)
else
vi->i_blocks = ni->_ICF(compressed_size) >> 9;
put_attr_search_ctx(ctx);
unmap_mft_record(READ, ni);
ntfs_debug("Done.");
return 0;
......@@ -1037,7 +1053,8 @@ static int ntfs_read_locked_inode(struct inode *vi)
err = -EIO;
if (ctx)
put_attr_search_ctx(ctx);
unmap_mft_record(READ, ni);
if (m)
unmap_mft_record(ni);
err_out:
ntfs_error(vi->i_sb, "Failed with error code %i. Marking inode 0x%lx "
"as bad.", -err, vi->i_ino);
......@@ -1091,7 +1108,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
/* Set inode type to zero but preserve permissions. */
vi->i_mode = base_vi->i_mode & ~S_IFMT;
m = map_mft_record(READ, base_ni);
m = map_mft_record(base_ni);
if (IS_ERR(m)) {
err = PTR_ERR(m);
goto err_out;
......@@ -1265,7 +1282,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
ni->nr_extents = -1;
put_attr_search_ctx(ctx);
unmap_mft_record(READ, base_ni);
unmap_mft_record(base_ni);
ntfs_debug("Done.");
return 0;
......@@ -1275,7 +1292,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
err = -EIO;
if (ctx)
put_attr_search_ctx(ctx);
unmap_mft_record(READ, base_ni);
unmap_mft_record(base_ni);
err_out:
ntfs_error(vi->i_sb, "Failed with error code %i while reading "
"attribute inode (mft_no 0x%lx, type 0x%x, name_len "
......@@ -1398,7 +1415,7 @@ void ntfs_read_inode_mount(struct inode *vi)
/* Need this to sanity check attribute list references to $MFT. */
ni->seq_no = le16_to_cpu(m->sequence_number);
/* Provides readpage() and sync_page() for map_mft_record(READ). */
/* Provides readpage() and sync_page() for map_mft_record(). */
vi->i_mapping->a_ops = &ntfs_mft_aops;
ctx = get_attr_search_ctx(ni, m);
......@@ -1795,8 +1812,8 @@ void __ntfs_clear_inode(ntfs_inode *ni)
}
}
/* Synchronize with ntfs_commit_inode(). */
down_write(&ni->mrec_lock);
up_write(&ni->mrec_lock);
down(&ni->mrec_lock);
up(&ni->mrec_lock);
if (NInoDirty(ni)) {
ntfs_error(ni->vol->sb, "Failed to commit dirty inode "
"asynchronously.");
......
......@@ -72,9 +72,8 @@ struct _ntfs_inode {
* The following fields are only valid for real inodes and extent
* inodes.
*/
struct rw_semaphore mrec_lock; /* Lock for serializing access to the
struct semaphore mrec_lock; /* Lock for serializing access to the
mft record belonging to this inode. */
atomic_t mft_count; /* Mapping reference count for book keeping. */
struct page *page; /* The page containing the mft record of the
inode. This should only be touched by the
(un)map_mft_record*() functions. */
......
......@@ -25,20 +25,6 @@
#include <linux/vmalloc.h>
#include <linux/slab.h>
/**
* vmalloc_nofs - allocate any pages but don't allow calls into fs layer
* @size: number of bytes to allocate
*
* Allocate any pages but don't allow calls into fs layer. Return allocated
* memory or NULL if insufficient memory.
*/
static inline void *vmalloc_nofs(unsigned long size)
{
if (likely(size >> PAGE_SHIFT < num_physpages))
return __vmalloc(size, GFP_NOFS | __GFP_HIGHMEM, PAGE_KERNEL);
return NULL;
}
/**
* ntfs_malloc_nofs - allocate memory in multiples of pages
* @size number of bytes to allocate
......@@ -66,7 +52,8 @@ static inline void *ntfs_malloc_nofs(unsigned long size)
static inline void ntfs_free(void *addr)
{
if (likely((unsigned long)addr < VMALLOC_START)) {
if (likely(((unsigned long)addr < VMALLOC_START) ||
((unsigned long)addr >= VMALLOC_END ))) {
return kfree(addr);
/* return free_page((unsigned long)addr); */
}
......
......@@ -2,7 +2,7 @@
* mft.c - NTFS kernel mft record operations. Part of the Linux-NTFS project.
*
* Copyright (c) 2001,2002 Anton Altaparmakov.
* Copyright (C) 2002 Richard Russon.
* Copyright (c) 2002 Richard Russon.
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
......@@ -85,13 +85,15 @@ int format_mft_record(ntfs_inode *ni, MFT_RECORD *mft_rec)
if (mft_rec)
m = mft_rec;
else {
m = map_mft_record(WRITE, ni);
m = map_mft_record(ni);
if (IS_ERR(m))
return PTR_ERR(m);
}
__format_mft_record(m, ni->vol->mft_record_size, ni->mft_no);
if (!mft_rec)
unmap_mft_record(WRITE, ni);
if (!mft_rec) {
// FIXME: Need to set the mft record dirty!
unmap_mft_record(ni);
}
return 0;
}
......@@ -132,7 +134,7 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni)
struct page *page;
unsigned long index, ofs, end_index;
BUG_ON(atomic_read(&ni->mft_count) || ni->page);
BUG_ON(ni->page);
/*
* The index into the page cache and the offset within the page cache
* page of the wanted mft record. FIXME: We need to check for
......@@ -146,70 +148,36 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni)
end_index = mft_vi->i_size >> PAGE_CACHE_SHIFT;
/* If the wanted index is out of bounds the mft record doesn't exist. */
if (index >= end_index) {
if (unlikely(index >= end_index)) {
if (index > end_index || (mft_vi->i_size & ~PAGE_CACHE_MASK) <
ofs + vol->mft_record_size) {
page = ERR_PTR(-ENOENT);
goto up_err_out;
goto err_out;
}
}
/* Read, map, and pin the page. */
page = ntfs_map_page(mft_vi->i_mapping, index);
if (!IS_ERR(page)) {
/* Pin the mft record mapping in the ntfs_inode. */
atomic_inc(&ni->mft_count);
/* Setup the references in the ntfs_inode. */
if (likely(!IS_ERR(page))) {
ni->page = page;
ni->page_ofs = ofs;
return page_address(page) + ofs;
}
up_err_out:
/* Just in case... */
err_out:
ni->page = NULL;
ni->page_ofs = 0;
ntfs_error(vol->sb, "Failed with error code %lu.", -PTR_ERR(page));
return (void*)page;
}
/**
* unmap_mft_record_page - unmap the page in which a specific mft record resides
* @ni: ntfs inode whose mft record page to unmap
*
* This unmaps the page in which the mft record of the ntfs inode @ni is
* situated and returns. This is a NOOP if highmem is not configured.
*
* The unmap happens via ntfs_unmap_page() which in turn decrements the use
* count on the page thus releasing it from the pinned state.
*
* We do not actually unmap the page from memory of course, as that will be
* done by the page cache code itself when memory pressure increases or
* whatever.
*/
static inline void unmap_mft_record_page(ntfs_inode *ni)
{
BUG_ON(atomic_read(&ni->mft_count) || !ni->page);
// TODO: If dirty, blah...
ntfs_unmap_page(ni->page);
ni->page = NULL;
ni->page_ofs = 0;
return;
}
/**
* map_mft_record - map, pin and lock an mft record
* @rw: map for read (rw = READ) or write (rw = WRITE)
* @ni: ntfs inode whose MFT record to map
*
* First, take the mrec_lock semaphore for reading or writing, depending on
* the value or @rw. We might now be sleeping, while waiting for the semaphore
* if it was already locked by someone else.
* First, take the mrec_lock semaphore. We might now be sleeping, while waiting
* for the semaphore if it was already locked by someone else.
*
* Then increment the map reference count and return the mft. If this is the
* first invocation, the page of the record is first mapped using
* map_mft_record_page().
* The page of the record is first mapped using map_mft_record_page() before
* being returned to the caller.
*
* This in turn uses ntfs_map_page() to get the page containing the wanted mft
* record (it in turn calls read_cache_page() which reads it in from disk if
......@@ -234,11 +202,11 @@ static inline void unmap_mft_record_page(ntfs_inode *ni)
* locking problem then is them locking the page while we are accessing it.
*
* So that code will end up having to own the mrec_lock of all mft
* records/inodes present in the page before I/O can proceed. Grr. In that
* case we wouldn't need need to bother with PG_locked and PG_uptodate as
* nobody will be accessing anything without owning the mrec_lock semaphore.
* But we do need to use them because of the read_cache_page() invokation and
* the code becomes so much simpler this way that it is well worth it.
* records/inodes present in the page before I/O can proceed. In that case we
* wouldn't need to bother with PG_locked and PG_uptodate as nobody will be
* accessing anything without owning the mrec_lock semaphore. But we do need
* to use them because of the read_cache_page() invokation and the code becomes
* so much simpler this way that it is well worth it.
*
* The mft record is now ours and we return a pointer to it. You need to check
* the returned pointer with IS_ERR() and if that is true, PTR_ERR() will return
......@@ -251,89 +219,75 @@ static inline void unmap_mft_record_page(ntfs_inode *ni)
* A: No, the inode ones mean we want to change the mft record, not we want to
* write it out.
*/
MFT_RECORD *map_mft_record(const int rw, ntfs_inode *ni)
MFT_RECORD *map_mft_record(ntfs_inode *ni)
{
MFT_RECORD *m;
ntfs_debug("Entering for mft_no 0x%lx, mapping for %s.", ni->mft_no,
rw == READ ? "READ" : "WRITE");
ntfs_debug("Entering for mft_no 0x%lx.", ni->mft_no);
/* Make sure the ntfs inode doesn't go away. */
atomic_inc(&ni->count);
/* Serialize access to this mft record. */
if (rw == READ)
down_read(&ni->mrec_lock);
else
down_write(&ni->mrec_lock);
/* If already mapped, bump reference count and return the mft record. */
if (atomic_read(&ni->mft_count)) {
BUG_ON(!ni->page);
atomic_inc(&ni->mft_count);
return page_address(ni->page) + ni->page_ofs;
}
down(&ni->mrec_lock);
/* Wasn't mapped. Map it now and return it if all was ok. */
m = map_mft_record_page(ni);
if (!IS_ERR(m))
if (likely(!IS_ERR(m)))
return m;
/* Mapping failed. Release the mft record lock. */
if (rw == READ)
up_read(&ni->mrec_lock);
else
up_write(&ni->mrec_lock);
ntfs_error(ni->vol->sb, "Failed with error code %lu.", -PTR_ERR(m));
/* Release the ntfs inode and return the error code. */
up(&ni->mrec_lock);
atomic_dec(&ni->count);
ntfs_error(ni->vol->sb, "Failed with error code %lu.", -PTR_ERR(m));
return m;
}
/**
* unmap_mft_record - release a mapped mft record
* @rw: unmap from read (@rw = READ) or write (@rw = WRITE)
* @ni: ntfs inode whose MFT record to unmap
*
* First, decrement the mapping count and when it reaches zero unmap the mft
* record.
* unmap_mft_record_page - unmap the page in which a specific mft record resides
* @ni: ntfs inode whose mft record page to unmap
*
* Second, release the mrec_lock semaphore.
* This unmaps the page in which the mft record of the ntfs inode @ni is
* situated and returns. This is a NOOP if highmem is not configured.
*
* The mft record is now released for others to get hold of.
* The unmap happens via ntfs_unmap_page() which in turn decrements the use
* count on the page thus releasing it from the pinned state.
*
* Finally, release the ntfs inode by decreasing the ntfs inode reference count.
* We do not actually unmap the page from memory of course, as that will be
* done by the page cache code itself when memory pressure increases or
* whatever.
*/
static inline void unmap_mft_record_page(ntfs_inode *ni)
{
BUG_ON(!ni->page);
// TODO: If dirty, blah...
ntfs_unmap_page(ni->page);
ni->page = NULL;
ni->page_ofs = 0;
return;
}
/**
* unmap_mft_record - release a mapped mft record
* @ni: ntfs inode whose MFT record to unmap
*
* NOTE: If caller had the mft record mapped for write and has modified it, it
* is imperative to set the mft record dirty BEFORE calling unmap_mft_record().
* We release the page mapping and the mrec_lock mutex which unmaps the mft
* record and releases it for others to get hold of. We also release the ntfs
* inode by decrementing the ntfs inode reference count.
*
* NOTE: This has to be done both for 'normal' mft records, and for extent mft
* records.
* NOTE: If caller has modified the mft record, it is imperative to set the mft
* record dirty BEFORE calling unmap_mft_record().
*/
void unmap_mft_record(const int rw, ntfs_inode *ni)
void unmap_mft_record(ntfs_inode *ni)
{
struct page *page = ni->page;
BUG_ON(!atomic_read(&ni->mft_count) || !page);
BUG_ON(!page);
ntfs_debug("Entering for mft_no 0x%lx, unmapping from %s.", ni->mft_no,
rw == READ ? "READ" : "WRITE");
ntfs_debug("Entering for mft_no 0x%lx.", ni->mft_no);
/* Only release the actual page mapping if this is the last one. */
if (atomic_dec_and_test(&ni->mft_count))
unmap_mft_record_page(ni);
/* Release the semaphore. */
if (rw == READ)
up_read(&ni->mrec_lock);
else
up_write(&ni->mrec_lock);
/* Release the ntfs inode. */
up(&ni->mrec_lock);
atomic_dec(&ni->count);
/*
* If pure ntfs_inode, i.e. no vfs inode attached, we leave it to
* ntfs_clear_extent_inode() in the extent inode case, and to the
......@@ -355,11 +309,6 @@ void unmap_mft_record(const int rw, ntfs_inode *ni)
*
* On successful return, @ntfs_ino contains a pointer to the ntfs_inode
* structure of the mapped extent inode.
*
* Note, we always map for READ. We consider this lock as irrelevant because
* the base inode will be write locked in all cases when we want to write to
* an extent inode which already gurantees that there is no-one else accessing
* the extent inode.
*/
MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
ntfs_inode **ntfs_ino)
......@@ -393,21 +342,21 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
break;
}
}
if (ni) {
if (likely(ni != NULL)) {
up(&base_ni->extent_lock);
atomic_dec(&base_ni->count);
/* We found the record; just have to map and return it. */
m = map_mft_record(READ, ni);
/* Map mft record increments this on success. */
m = map_mft_record(ni);
/* map_mft_record() has incremented this on success. */
atomic_dec(&ni->count);
if (!IS_ERR(m)) {
if (likely(!IS_ERR(m))) {
/* Verify the sequence number. */
if (le16_to_cpu(m->sequence_number) == seq_no) {
if (likely(le16_to_cpu(m->sequence_number) == seq_no)) {
ntfs_debug("Done 1.");
*ntfs_ino = ni;
return m;
}
unmap_mft_record(READ, ni);
unmap_mft_record(ni);
ntfs_error(base_ni->vol->sb, "Found stale extent mft "
"reference! Corrupt file system. "
"Run chkdsk.");
......@@ -420,7 +369,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
}
/* Record wasn't there. Get a new ntfs inode and initialize it. */
ni = ntfs_new_extent_inode(base_ni->vol->sb, mft_no);
if (!ni) {
if (unlikely(!ni)) {
up(&base_ni->extent_lock);
atomic_dec(&base_ni->count);
return ERR_PTR(-ENOMEM);
......@@ -430,15 +379,15 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
ni->nr_extents = -1;
ni->_INE(base_ntfs_ino) = base_ni;
/* Now map the record. */
m = map_mft_record(READ, ni);
if (IS_ERR(m)) {
m = map_mft_record(ni);
if (unlikely(IS_ERR(m))) {
up(&base_ni->extent_lock);
atomic_dec(&base_ni->count);
ntfs_clear_extent_inode(ni);
goto map_err_out;
}
/* Verify the sequence number. */
if (le16_to_cpu(m->sequence_number) != seq_no) {
if (unlikely(le16_to_cpu(m->sequence_number) != seq_no)) {
ntfs_error(base_ni->vol->sb, "Found stale extent mft "
"reference! Corrupt file system. Run chkdsk.");
destroy_ni = TRUE;
......@@ -451,7 +400,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
int new_size = (base_ni->nr_extents + 4) * sizeof(ntfs_inode *);
tmp = (ntfs_inode **)kmalloc(new_size, GFP_NOFS);
if (!tmp) {
if (unlikely(!tmp)) {
ntfs_error(base_ni->vol->sb, "Failed to allocate "
"internal buffer.");
destroy_ni = TRUE;
......@@ -472,7 +421,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
*ntfs_ino = ni;
return m;
unm_err_out:
unmap_mft_record(READ, ni);
unmap_mft_record(ni);
up(&base_ni->extent_lock);
atomic_dec(&base_ni->count);
/*
......
......@@ -31,15 +31,15 @@ extern int format_mft_record(ntfs_inode *ni, MFT_RECORD *m);
//extern int format_mft_record2(struct super_block *vfs_sb,
// const unsigned long inum, MFT_RECORD *m);
extern MFT_RECORD *map_mft_record(const int rw, ntfs_inode *ni);
extern void unmap_mft_record(const int rw, ntfs_inode *ni);
extern MFT_RECORD *map_mft_record(ntfs_inode *ni);
extern void unmap_mft_record(ntfs_inode *ni);
extern MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
ntfs_inode **ntfs_ino);
static inline void unmap_extent_mft_record(ntfs_inode *ni)
{
unmap_mft_record(READ, ni);
unmap_mft_record(ni);
return;
}
......
......@@ -162,6 +162,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent)
handle_name:
{
struct dentry *real_dent;
MFT_RECORD *m;
attr_search_context *ctx;
ntfs_inode *ni = NTFS_I(dent_inode);
int err;
......@@ -175,22 +176,23 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent)
name->len * 3 + 1);
kfree(name);
} else /* if (name->type == FILE_NAME_DOS) */ { /* Case 3. */
MFT_RECORD *m;
FILE_NAME_ATTR *fn;
kfree(name);
/* Find the WIN32 name corresponding to the matched DOS name. */
ni = NTFS_I(dent_inode);
m = map_mft_record(READ, ni);
m = map_mft_record(ni);
if (IS_ERR(m)) {
err = PTR_ERR(m);
goto name_err_out;
m = NULL;
ctx = NULL;
goto err_out;
}
ctx = get_attr_search_ctx(ni, m);
if (!ctx) {
err = -ENOMEM;
goto unm_err_out;
goto err_out;
}
do {
ATTR_RECORD *a;
......@@ -202,21 +204,21 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent)
"namespace counterpart to DOS "
"file name. Run chkdsk.");
err = -EIO;
goto put_unm_err_out;
goto err_out;
}
/* Consistency checks. */
a = ctx->attr;
if (a->non_resident || a->flags)
goto eio_put_unm_err_out;
goto eio_err_out;
val_len = le32_to_cpu(a->_ARA(value_length));
if (le16_to_cpu(a->_ARA(value_offset)) + val_len >
le32_to_cpu(a->length))
goto eio_put_unm_err_out;
goto eio_err_out;
fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + le16_to_cpu(
ctx->attr->_ARA(value_offset)));
if ((u32)(fn->file_name_length * sizeof(uchar_t) +
sizeof(FILE_NAME_ATTR)) > val_len)
goto eio_put_unm_err_out;
goto eio_err_out;
} while (fn->file_name_type != FILE_NAME_WIN32);
/* Convert the found WIN32 name to current NLS code page. */
......@@ -226,13 +228,15 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent)
fn->file_name_length * 3 + 1);
put_attr_search_ctx(ctx);
unmap_mft_record(READ, ni);
unmap_mft_record(ni);
}
m = NULL;
ctx = NULL;
/* Check if a conversion error occured. */
if ((signed)nls_name.len < 0) {
err = (signed)nls_name.len;
goto name_err_out;
goto err_out;
}
nls_name.hash = full_name_hash(nls_name.name, nls_name.len);
......@@ -248,7 +252,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent)
kfree(nls_name.name);
if (!real_dent) {
err = -ENOMEM;
goto name_err_out;
goto err_out;
}
d_add(real_dent, dent_inode);
return real_dent;
......@@ -269,14 +273,14 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent)
d_instantiate(real_dent, dent_inode);
return real_dent;
eio_put_unm_err_out:
eio_err_out:
ntfs_error(vol->sb, "Illegal file name attribute. Run chkdsk.");
err = -EIO;
put_unm_err_out:
err_out:
if (ctx)
put_attr_search_ctx(ctx);
unm_err_out:
unmap_mft_record(READ, ni);
name_err_out:
if (m)
unmap_mft_record(ni);
iput(dent_inode);
return ERR_PTR(err);
}
......
......@@ -307,6 +307,23 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt)
ntfs_debug("Entering with remount options string: %s", opt);
#ifndef NTFS_RW
/* For read-only compiled driver, enforce all read-only flags. */
*flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
#else
/*
* For the read-write compiled driver, if we are remounting read-write,
* make sure there aren't any volume errors.
*/
if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) {
if (NVolErrors(vol)) {
ntfs_error(sb, "Volume has errors and is read-only."
"Cannot remount read-write.");
return -EROFS;
}
}
#endif
// FIXME/TODO: If left like this we will have problems with rw->ro and
// ro->rw, as well as with sync->async and vice versa remounts.
// Note: The VFS already checks that there are no pending deletes and
......@@ -324,10 +341,6 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt)
if (!parse_options(vol, opt))
return -EINVAL;
#ifndef NTFS_RW
*flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
#endif
return 0;
}
......@@ -852,7 +865,7 @@ static BOOL load_system_files(ntfs_volume *vol)
ntfs_error(sb, "Failed to load $Volume.");
goto iput_lcnbmp_err_out;
}
m = map_mft_record(READ, NTFS_I(vol->vol_ino));
m = map_mft_record(NTFS_I(vol->vol_ino));
if (IS_ERR(m)) {
iput_volume_failed:
iput(vol->vol_ino);
......@@ -867,7 +880,7 @@ static BOOL load_system_files(ntfs_volume *vol)
err_put_vol:
put_attr_search_ctx(ctx);
get_ctx_vol_failed:
unmap_mft_record(READ, NTFS_I(vol->vol_ino));
unmap_mft_record(NTFS_I(vol->vol_ino));
goto iput_volume_failed;
}
vi = (VOLUME_INFORMATION*)((char*)ctx->attr +
......@@ -882,7 +895,7 @@ static BOOL load_system_files(ntfs_volume *vol)
vol->major_ver = vi->major_ver;
vol->minor_ver = vi->minor_ver;
put_attr_search_ctx(ctx);
unmap_mft_record(READ, NTFS_I(vol->vol_ino));
unmap_mft_record(NTFS_I(vol->vol_ino));
printk(KERN_INFO "NTFS volume version %i.%i.\n", vol->major_ver,
vol->minor_ver);
/*
......
......@@ -101,6 +101,7 @@ typedef struct {
* Defined bits for the flags field in the ntfs_volume structure.
*/
typedef enum {
NV_Errors, /* 1: Volume has errors, prevent remount rw. */
NV_ShowSystemFiles, /* 1: Return system files in ntfs_readdir(). */
NV_CaseSensitive, /* 1: Treat file names as case sensitive and
create filenames in the POSIX namespace.
......@@ -127,6 +128,7 @@ static inline void NVolClear##flag(ntfs_volume *vol) \
}
/* Emit the ntfs volume bitops functions. */
NVOL_FNS(Errors)
NVOL_FNS(ShowSystemFiles)
NVOL_FNS(CaseSensitive)
......
......@@ -245,18 +245,12 @@ typedef struct {
#define ISDN_TIMER_MODEMPLUS 2
#define ISDN_TIMER_MODEMRING 4
#define ISDN_TIMER_MODEMXMIT 8
#define ISDN_TIMER_NETDIAL 16
#define ISDN_TIMER_NETHANGUP 32
#define ISDN_TIMER_CARRIER 256 /* Wait for Carrier */
#define ISDN_TIMER_FAST (ISDN_TIMER_MODEMREAD | ISDN_TIMER_MODEMPLUS | \
ISDN_TIMER_MODEMXMIT)
#define ISDN_TIMER_SLOW (ISDN_TIMER_MODEMRING | ISDN_TIMER_NETHANGUP | \
ISDN_TIMER_NETDIAL | ISDN_TIMER_CARRIER)
/* Timeout-Values for isdn_net_dial() */
#define ISDN_TIMER_DTIMEOUT10 (10*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1)))
#define ISDN_TIMER_DTIMEOUT15 (15*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1)))
#define ISDN_TIMER_DTIMEOUT60 (60*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1)))
ISDN_TIMER_CARRIER)
/* GLOBAL_FLAGS */
#define ISDN_GLOBAL_STOPPED 1
......@@ -291,9 +285,10 @@ typedef struct {
typedef struct isdn_net_local_s {
ulong magic;
char name[10]; /* Name of device */
struct timer_list dial_timer; /* dial timeout */
int dial_event; /* event in case of timer expiry */
struct net_device_stats stats; /* Ethernet Statistics */
int isdn_device; /* Index to isdn-device */
int isdn_channel; /* Index to isdn-channel */
int isdn_slot; /* Index to isdn device/channel */
int ppp_slot; /* PPPD device slot number */
int pre_device; /* Preselected isdn-device */
int pre_channel; /* Preselected isdn-channel */
......@@ -302,7 +297,6 @@ typedef struct isdn_net_local_s {
int dialretry; /* Counter for Dialout-retries */
int dialmax; /* Max. Number of Dial-retries */
int cbdelay; /* Delay before Callback starts */
int dtimer; /* Timeout-counter for dialing */
char msn[ISDN_MSNLEN]; /* MSNs/EAZs for this interface */
u_char cbhup; /* Flag: Reject Call before Callback*/
u_char dialstate; /* State for dialing */
......@@ -387,12 +381,12 @@ typedef struct isdn_net_local_s {
/* the interface itself */
typedef struct isdn_net_dev_s {
isdn_net_local *local;
isdn_net_local local;
isdn_net_local *queue; /* circular list of all bundled
channels, which are currently
online */
spinlock_t queue_lock; /* lock to protect queue */
void *next; /* Pointer to next isdn-interface */
struct list_head global_list; /* global list of all isdn_net_devs */
struct net_device dev; /* interface to upper levels */
#ifdef CONFIG_ISDN_PPP
ippp_bundle * pb; /* pointer to the common bundle structure
......@@ -480,9 +474,7 @@ typedef struct modem_info {
/* 2 = B-Channel is up, deliver d.*/
int dialing; /* Dial in progress or ATA */
int rcvsched; /* Receive needs schedule */
int isdn_driver; /* Index to isdn-driver */
int isdn_channel; /* Index to isdn-channel */
int drv_index; /* Index to dev->usage */
int isdn_slot; /* Index to isdn-driver/channel */
int ncarrier; /* Flag: schedule NO CARRIER */
unsigned char last_cause[8]; /* Last cause message */
unsigned char last_num[ISDN_MSNLEN];
......@@ -608,24 +600,10 @@ typedef struct isdn_devt {
infostruct *infochain; /* List of open info-devs. */
wait_queue_head_t info_waitq; /* Wait-Queue for isdninfo */
struct timer_list timer; /* Misc.-function Timer */
int chanmap[ISDN_MAX_CHANNELS];/* Map minor->device-channel */
int drvmap[ISDN_MAX_CHANNELS]; /* Map minor->driver-index */
int usage[ISDN_MAX_CHANNELS]; /* Used by tty/ip/voice */
char num[ISDN_MAX_CHANNELS][ISDN_MSNLEN];
/* Remote number of active ch.*/
int m_idx[ISDN_MAX_CHANNELS]; /* Index for mdm.... */
driver *drv[ISDN_MAX_DRIVERS]; /* Array of drivers */
isdn_net_dev *netdev; /* Linked list of net-if's */
char drvid[ISDN_MAX_DRIVERS][20];/* Driver-ID */
struct task_struct *profd; /* For iprofd */
modem mdm; /* tty-driver-data */
isdn_net_dev *rx_netdev[ISDN_MAX_CHANNELS]; /* rx netdev-pointers */
isdn_net_dev *st_netdev[ISDN_MAX_CHANNELS]; /* stat netdev-pointers */
ulong ibytes[ISDN_MAX_CHANNELS]; /* Statistics incoming bytes */
ulong obytes[ISDN_MAX_CHANNELS]; /* Statistics outgoing bytes */
int v110emu[ISDN_MAX_CHANNELS];/* V.110 emulator-mode 0=none */
atomic_t v110use[ISDN_MAX_CHANNELS];/* Usage-Semaphore for stream */
isdn_v110_stream *v110[ISDN_MAX_CHANNELS]; /* V.110 private data */
struct semaphore sem; /* serialize list access*/
unsigned long global_features;
#ifdef CONFIG_DEVFS_FS
......
......@@ -418,9 +418,7 @@ typedef struct {
char display[85];/* display message data */
isdn_cmd_stat isdn_io; /* ISDN IO-parameter/result */
aux_s aux; /* for modem commands/indications */
#ifdef CONFIG_ISDN_TTY_FAX
T30_s *fax; /* Pointer to ttys fax struct */
#endif
ulong userdata; /* User Data */
} parm;
} isdn_ctrl;
......
......@@ -422,6 +422,7 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
{
struct mm_struct * mm = current->mm;
struct vm_area_struct * vma, * prev;
struct inode *inode = NULL;
unsigned int vm_flags;
int correct_wcount = 0;
int error;
......@@ -469,17 +470,18 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
}
if (file) {
inode = file->f_dentry->d_inode;
switch (flags & MAP_TYPE) {
case MAP_SHARED:
if ((prot & PROT_WRITE) && !(file->f_mode & FMODE_WRITE))
return -EACCES;
/* Make sure we don't allow writing to an append-only file.. */
if (IS_APPEND(file->f_dentry->d_inode) && (file->f_mode & FMODE_WRITE))
if (IS_APPEND(inode) && (file->f_mode & FMODE_WRITE))
return -EACCES;
/* make sure there are no mandatory locks on the file. */
if (locks_verify_locked(file->f_dentry->d_inode))
if (locks_verify_locked(inode))
return -EAGAIN;
vm_flags |= VM_SHARED | VM_MAYSHARE;
......@@ -603,7 +605,7 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
vma_link(mm, vma, prev, rb_link, rb_parent);
if (correct_wcount)
atomic_inc(&file->f_dentry->d_inode->i_writecount);
atomic_inc(&inode->i_writecount);
out:
mm->total_vm += len >> PAGE_SHIFT;
......@@ -615,7 +617,7 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
unmap_and_free_vma:
if (correct_wcount)
atomic_inc(&file->f_dentry->d_inode->i_writecount);
atomic_inc(&inode->i_writecount);
vma->vm_file = NULL;
fput(file);
......@@ -755,38 +757,41 @@ struct vm_area_struct * find_vma_prev(struct mm_struct * mm, unsigned long addr,
return prev ? prev->vm_next : vma;
}
#ifdef ARCH_STACK_GROWSUP
/*
* vma is the first one with address < vma->vm_end,
* and even address < vma->vm_start. Have to extend vma.
* vma is the first one with address > vma->vm_end. Have to extend vma.
*/
int expand_stack(struct vm_area_struct * vma, unsigned long address)
{
unsigned long grow;
if (!(vma->vm_flags & VM_GROWSUP))
return -EFAULT;
/*
* vma->vm_start/vm_end cannot change under us because the caller
* is required to hold the mmap_sem in write mode. We need to get
* is required to hold the mmap_sem in read mode. We need to get
* the spinlock only before relocating the vma range ourself.
*/
address += 4 + PAGE_SIZE - 1;
address &= PAGE_MASK;
spin_lock(&vma->vm_mm->page_table_lock);
grow = (vma->vm_start - address) >> PAGE_SHIFT;
grow = (address - vma->vm_end) >> PAGE_SHIFT;
/* Overcommit.. */
if(!vm_enough_memory(grow)) {
if (!vm_enough_memory(grow)) {
spin_unlock(&vma->vm_mm->page_table_lock);
return -ENOMEM;
}
if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur ||
if (address - vma->vm_start > current->rlim[RLIMIT_STACK].rlim_cur ||
((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) >
current->rlim[RLIMIT_AS].rlim_cur) {
spin_unlock(&vma->vm_mm->page_table_lock);
vm_unacct_memory(grow);
return -ENOMEM;
}
vma->vm_start = address;
vma->vm_pgoff -= grow;
vma->vm_end = address;
vma->vm_mm->total_vm += grow;
if (vma->vm_flags & VM_LOCKED)
vma->vm_mm->locked_vm += grow;
......@@ -794,7 +799,6 @@ int expand_stack(struct vm_area_struct * vma, unsigned long address)
return 0;
}
#ifdef ARCH_STACK_GROWSUP
struct vm_area_struct * find_extend_vma(struct mm_struct * mm, unsigned long addr)
{
struct vm_area_struct *vma, *prev;
......@@ -811,6 +815,44 @@ struct vm_area_struct * find_extend_vma(struct mm_struct * mm, unsigned long add
return prev;
}
#else
/*
* vma is the first one with address < vma->vm_start. Have to extend vma.
*/
int expand_stack(struct vm_area_struct * vma, unsigned long address)
{
unsigned long grow;
/*
* vma->vm_start/vm_end cannot change under us because the caller
* is required to hold the mmap_sem in read mode. We need to get
* the spinlock only before relocating the vma range ourself.
*/
address &= PAGE_MASK;
spin_lock(&vma->vm_mm->page_table_lock);
grow = (vma->vm_start - address) >> PAGE_SHIFT;
/* Overcommit.. */
if (!vm_enough_memory(grow)) {
spin_unlock(&vma->vm_mm->page_table_lock);
return -ENOMEM;
}
if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur ||
((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) >
current->rlim[RLIMIT_AS].rlim_cur) {
spin_unlock(&vma->vm_mm->page_table_lock);
vm_unacct_memory(grow);
return -ENOMEM;
}
vma->vm_start = address;
vma->vm_pgoff -= grow;
vma->vm_mm->total_vm += grow;
if (vma->vm_flags & VM_LOCKED)
vma->vm_mm->locked_vm += grow;
spin_unlock(&vma->vm_mm->page_table_lock);
return 0;
}
struct vm_area_struct * find_extend_vma(struct mm_struct * mm, unsigned long addr)
{
struct vm_area_struct * vma;
......
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