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