Commit cd2d00c6 authored by Kai Germaschewski's avatar Kai Germaschewski

ISDN: Lock list of phone numbers appropriately

It was (only partially) protected by cli() before, which we want to
get rid of.
parent 51430a3c
...@@ -1599,8 +1599,9 @@ static struct file_operations isdn_ctrl_fops = ...@@ -1599,8 +1599,9 @@ static struct file_operations isdn_ctrl_fops =
.release = isdn_ctrl_release, .release = isdn_ctrl_release,
}; };
/* /*
* file_operations for major 43, /dev/isdn* * file_operations for major 45, /dev/isdn*
* stolen from drivers/char/misc.c * stolen from drivers/char/misc.c
*/ */
......
...@@ -486,12 +486,7 @@ isdn_net_dial_timer(unsigned long data) ...@@ -486,12 +486,7 @@ isdn_net_dial_timer(unsigned long data)
static void static void
init_dialout(isdn_net_local *lp) init_dialout(isdn_net_local *lp)
{ {
unsigned long flags;
save_flags(flags);
cli();
lp->dial = 0; lp->dial = 0;
restore_flags(flags);
if (lp->dialtimeout > 0 && if (lp->dialtimeout > 0 &&
(lp->dialstarted == 0 || (lp->dialstarted == 0 ||
...@@ -524,9 +519,11 @@ do_dialout(isdn_net_local *lp) ...@@ -524,9 +519,11 @@ do_dialout(isdn_net_local *lp)
if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF)
return; return;
if (list_empty(&lp->phone[1])) spin_lock_irqsave(&lp->lock, flags);
if (list_empty(&lp->phone[1])) {
spin_unlock_irqrestore(&lp->lock, flags);
return; return;
}
i = 0; i = 0;
list_for_each_entry(phone, &lp->phone[1], list) { list_for_each_entry(phone, &lp->phone[1], list) {
if (i++ == lp->dial) if (i++ == lp->dial)
...@@ -537,6 +534,11 @@ do_dialout(isdn_net_local *lp) ...@@ -537,6 +534,11 @@ do_dialout(isdn_net_local *lp)
lp->dial = 0; lp->dial = 0;
lp->dialretry++; lp->dialretry++;
found:
lp->dial++;
dial.phone = phone->num;
spin_unlock_irqrestore(&lp->lock, flags);
if (lp->dialretry > lp->dialmax) { if (lp->dialretry > lp->dialmax) {
if (lp->dialtimeout == 0) { if (lp->dialtimeout == 0) {
lp->dialwait_timer = jiffies + lp->dialwait; lp->dialwait_timer = jiffies + lp->dialwait;
...@@ -545,17 +547,12 @@ do_dialout(isdn_net_local *lp) ...@@ -545,17 +547,12 @@ do_dialout(isdn_net_local *lp)
isdn_net_hangup(lp); isdn_net_hangup(lp);
return; return;
} }
found:
lp->dial++;
dial.phone = phone->num;
if(lp->dialtimeout > 0 && if(lp->dialtimeout > 0 &&
time_after(jiffies, lp->dialstarted + lp->dialtimeout)) { time_after(jiffies, lp->dialstarted + lp->dialtimeout)) {
lp->dialwait_timer = jiffies + lp->dialwait; lp->dialwait_timer = jiffies + lp->dialwait;
lp->dialstarted = 0; lp->dialstarted = 0;
isdn_net_hangup(lp); isdn_net_hangup(lp);
return; return;
} }
/* /*
* 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.
...@@ -2219,10 +2216,14 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) ...@@ -2219,10 +2216,14 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
} }
dbg_net_icall("n_fi: match2\n"); dbg_net_icall("n_fi: match2\n");
if (lp->flags & ISDN_NET_SECURE) { if (lp->flags & ISDN_NET_SECURE) {
spin_lock_irqsave(&lp->lock, flags);
list_for_each_entry(n, &lp->phone[0], list) { list_for_each_entry(n, &lp->phone[0], list) {
if (!isdn_msncmp(nr, n->num)) if (!isdn_msncmp(nr, n->num)) {
spin_unlock_irqrestore(&lp->lock, flags);
break; break;
}
} }
spin_unlock_irqrestore(&lp->lock, flags);
continue; continue;
} }
dbg_net_icall("n_fi: match3\n"); dbg_net_icall("n_fi: match3\n");
...@@ -2557,6 +2558,9 @@ isdn_net_new(char *name, struct net_device *master) ...@@ -2557,6 +2558,9 @@ isdn_net_new(char *name, struct net_device *master)
init_timer(&netdev->local.hup_timer); init_timer(&netdev->local.hup_timer);
netdev->local.hup_timer.data = (unsigned long) &netdev->local; netdev->local.hup_timer.data = (unsigned long) &netdev->local;
netdev->local.hup_timer.function = isdn_net_hup_timer; netdev->local.hup_timer.function = isdn_net_hup_timer;
spin_lock_init(&netdev->local.lock);
INIT_LIST_HEAD(&netdev->local.phone[0]);
INIT_LIST_HEAD(&netdev->local.phone[1]);
/* Put into to netdev-chain */ /* Put into to netdev-chain */
list_add(&netdev->global_list, &isdn_net_devs); list_add(&netdev->global_list, &isdn_net_devs);
...@@ -2889,6 +2893,7 @@ int ...@@ -2889,6 +2893,7 @@ int
isdn_net_addphone(isdn_net_ioctl_phone * phone) isdn_net_addphone(isdn_net_ioctl_phone * phone)
{ {
isdn_net_dev *p = isdn_net_findif(phone->name); isdn_net_dev *p = isdn_net_findif(phone->name);
unsigned long flags;
struct isdn_net_phone *n; struct isdn_net_phone *n;
if (!p) if (!p)
...@@ -2899,7 +2904,9 @@ isdn_net_addphone(isdn_net_ioctl_phone * phone) ...@@ -2899,7 +2904,9 @@ isdn_net_addphone(isdn_net_ioctl_phone * phone)
return -ENOMEM; return -ENOMEM;
strcpy(n->num, phone->phone); strcpy(n->num, phone->phone);
spin_lock_irqsave(&p->local.lock, flags);
list_add_tail(&n->list, &p->local.phone[phone->outgoing & 1]); list_add_tail(&n->list, &p->local.phone[phone->outgoing & 1]);
spin_unlock_irqrestore(&p->local.lock, flags);
return 0; return 0;
} }
...@@ -2911,32 +2918,37 @@ int ...@@ -2911,32 +2918,37 @@ int
isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones) isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones)
{ {
isdn_net_dev *p = isdn_net_findif(phone->name); isdn_net_dev *p = isdn_net_findif(phone->name);
unsigned long flags;
int inout = phone->outgoing & 1; int inout = phone->outgoing & 1;
int more = 0;
int count = 0; int count = 0;
char *buf = (char *)__get_free_page(GFP_KERNEL);
struct isdn_net_phone *n; struct isdn_net_phone *n;
if (!p) if (!p)
return -ENODEV; return -ENODEV;
if (!buf)
return -ENOMEM;
inout &= 1; inout &= 1;
spin_lock_irqsave(&p->local.lock, flags);
list_for_each_entry(n, &p->local.phone[inout], list) { list_for_each_entry(n, &p->local.phone[inout], list) {
if (more) { strcpy(&buf[count], n->num);
if (put_user(' ', phones++))
return -EFAULT;
count++;
}
if (copy_to_user(phones, n->num, strlen(n->num) + 1)) {
return -EFAULT;
}
phones += strlen(n->num);
count += strlen(n->num); count += strlen(n->num);
more = 1; buf[count++] = ' ';
if (count > PAGE_SIZE - ISDN_MSNLEN - 1)
break;
} }
if (put_user(0, phones)) spin_unlock_irqrestore(&p->local.lock, flags);
return -EFAULT; if (!count)
count++;
buf[count-1] = 0;
count++; if (copy_to_user(phones, buf, count))
count = -EFAULT;
free_page((unsigned long)buf);
return count; return count;
} }
...@@ -2976,22 +2988,23 @@ isdn_net_delphone(isdn_net_ioctl_phone * phone) ...@@ -2976,22 +2988,23 @@ isdn_net_delphone(isdn_net_ioctl_phone * phone)
int inout = phone->outgoing & 1; int inout = phone->outgoing & 1;
struct isdn_net_phone *n; struct isdn_net_phone *n;
unsigned long flags; unsigned long flags;
int retval;
if (!p) if (!p)
return -ENODEV; return -ENODEV;
save_flags(flags); retval = -EINVAL;
cli(); spin_lock_irqsave(&p->local.lock, flags);
list_for_each_entry(n, &p->local.phone[inout], list) { list_for_each_entry(n, &p->local.phone[inout], list) {
if (!strcmp(n->num, phone->phone)) { if (!strcmp(n->num, phone->phone)) {
list_del(&n->list); list_del(&n->list);
kfree(n); kfree(n);
restore_flags(flags); retval = 0;
return 0; break;
} }
} }
restore_flags(flags); spin_unlock_irqrestore(&p->local.lock, flags);
return -EINVAL; return retval;
} }
/* /*
...@@ -3004,8 +3017,7 @@ isdn_net_rmallphone(isdn_net_dev * p) ...@@ -3004,8 +3017,7 @@ isdn_net_rmallphone(isdn_net_dev * p)
unsigned long flags; unsigned long flags;
int i; int i;
save_flags(flags); spin_lock_irqsave(&p->local.lock, flags);
cli();
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
while (!list_empty(&p->local.phone[i])) { while (!list_empty(&p->local.phone[i])) {
n = list_entry(p->local.phone[i].next, struct isdn_net_phone, list); n = list_entry(p->local.phone[i].next, struct isdn_net_phone, list);
...@@ -3013,8 +3025,7 @@ isdn_net_rmallphone(isdn_net_dev * p) ...@@ -3013,8 +3025,7 @@ isdn_net_rmallphone(isdn_net_dev * p)
kfree(n); kfree(n);
} }
} }
p->local.dial = 0; spin_lock_irqsave(&p->local.lock, flags);
restore_flags(flags);
return 0; return 0;
} }
......
...@@ -281,6 +281,7 @@ struct isdn_net_phone { ...@@ -281,6 +281,7 @@ struct isdn_net_phone {
/* Local interface-data */ /* Local interface-data */
typedef struct isdn_net_local_s { typedef struct isdn_net_local_s {
spinlock_t lock;
ulong magic; ulong magic;
char name[10]; /* Name of device */ char name[10]; /* Name of device */
struct timer_list dial_timer; /* dial events timer */ struct timer_list dial_timer; /* dial events timer */
......
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