Commit 51430a3c authored by Kai Germaschewski's avatar Kai Germaschewski

ISDN: Use <linux/list.h> for list of phone numbers

Simplifies the code which was previously using an open coded
singly linked list.

Also, deleting a phone number during dial-out could easily oops
the kernel before this patch.
parent 7e22da6a
...@@ -490,15 +490,9 @@ init_dialout(isdn_net_local *lp) ...@@ -490,15 +490,9 @@ init_dialout(isdn_net_local *lp)
save_flags(flags); save_flags(flags);
cli(); cli();
lp->dial = lp->phone[1]; lp->dial = 0;
restore_flags(flags); restore_flags(flags);
if (!lp->dial) {
printk(KERN_WARNING "%s: phone number deleted?\n",
lp->name);
isdn_net_hangup(lp);
return;
}
if (lp->dialtimeout > 0 && if (lp->dialtimeout > 0 &&
(lp->dialstarted == 0 || (lp->dialstarted == 0 ||
time_after(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait))) { time_after(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait))) {
...@@ -516,38 +510,34 @@ init_dialout(isdn_net_local *lp) ...@@ -516,38 +510,34 @@ init_dialout(isdn_net_local *lp)
static void static void
do_dialout(isdn_net_local *lp) do_dialout(isdn_net_local *lp)
{ {
int i;
unsigned long flags; unsigned long flags;
struct isdn_net_phone *phone;
struct dial_info dial = { struct dial_info dial = {
.l2_proto = lp->l2_proto, .l2_proto = lp->l2_proto,
.l3_proto = lp->l3_proto, .l3_proto = lp->l3_proto,
.si1 = 7, .si1 = 7,
.si2 = 0, .si2 = 0,
.msn = lp->msn, .msn = lp->msn,
.phone = lp->dial->num,
}; };
if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF)
return; return;
save_flags(flags); if (list_empty(&lp->phone[1]))
cli();
if(lp->dialtimeout > 0 &&
time_after(jiffies, lp->dialstarted + lp->dialtimeout)) {
restore_flags(flags);
lp->dialwait_timer = jiffies + lp->dialwait;
lp->dialstarted = 0;
isdn_net_hangup(lp);
return; return;
i = 0;
list_for_each_entry(phone, &lp->phone[1], list) {
if (i++ == lp->dial)
goto found;
} }
/* /* otherwise start in front */
* Switch to next number or back to start if at end of list. phone = list_entry(lp->phone[1].next, struct isdn_net_phone, list);
*/ lp->dial = 0;
if (!(lp->dial = lp->dial->next)) {
lp->dial = lp->phone[1];
lp->dialretry++; lp->dialretry++;
if (lp->dialretry > lp->dialmax) { if (lp->dialretry > lp->dialmax) {
restore_flags(flags);
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;
...@@ -555,8 +545,21 @@ do_dialout(isdn_net_local *lp) ...@@ -555,8 +545,21 @@ 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 &&
time_after(jiffies, lp->dialstarted + lp->dialtimeout)) {
lp->dialwait_timer = jiffies + lp->dialwait;
lp->dialstarted = 0;
isdn_net_hangup(lp);
return;
} }
restore_flags(flags); /*
* Switch to next number or back to start if at end of list.
*/
isdn_slot_dial(lp->isdn_slot, &dial); isdn_slot_dial(lp->isdn_slot, &dial);
lp->huptimer = 0; lp->huptimer = 0;
...@@ -1136,6 +1139,7 @@ void isdn_net_tx_timeout(struct net_device * ndev) ...@@ -1136,6 +1139,7 @@ void isdn_net_tx_timeout(struct net_device * ndev)
static int static int
isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{ {
unsigned long flags;
isdn_net_local *lp = (isdn_net_local *) ndev->priv; isdn_net_local *lp = (isdn_net_local *) ndev->priv;
#ifdef CONFIG_ISDN_X25 #ifdef CONFIG_ISDN_X25
struct concap_proto * cprot = lp -> netdev -> cprot; struct concap_proto * cprot = lp -> netdev -> cprot;
...@@ -1171,8 +1175,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) ...@@ -1171,8 +1175,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
dev_kfree_skb(skb); dev_kfree_skb(skb);
return 0; return 0;
} }
if (lp->phone[1]) {
ulong flags;
save_flags(flags); save_flags(flags);
cli(); cli();
...@@ -1239,12 +1242,6 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) ...@@ -1239,12 +1242,6 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
init_dialout(lp); init_dialout(lp);
isdn_net_device_stop_queue(lp); isdn_net_device_stop_queue(lp);
return 1; return 1;
} else {
isdn_net_unreachable(ndev, skb,
"No phone number");
dev_kfree_skb(skb);
return 0;
}
} else { } else {
/* Device is connected to an ISDN channel */ /* Device is connected to an ISDN channel */
ndev->trans_start = jiffies; ndev->trans_start = jiffies;
...@@ -2221,15 +2218,13 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) ...@@ -2221,15 +2218,13 @@ 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");
n = lp->phone[0];
if (lp->flags & ISDN_NET_SECURE) { if (lp->flags & ISDN_NET_SECURE) {
while (n) { list_for_each_entry(n, &lp->phone[0], list) {
if (!isdn_msncmp(nr, n->num)) if (!isdn_msncmp(nr, n->num))
break; break;
n = n->next;
} }
continue;
} }
if (n || (!(lp->flags & ISDN_NET_SECURE))) {
dbg_net_icall("n_fi: match3\n"); dbg_net_icall("n_fi: match3\n");
/* matching interface found */ /* matching interface found */
...@@ -2292,7 +2287,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) ...@@ -2292,7 +2287,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
} }
printk(KERN_DEBUG "%s: call from %s -> %s, start callback\n", printk(KERN_DEBUG "%s: call from %s -> %s, start callback\n",
lp->name, nr, eaz); lp->name, nr, eaz);
if (lp->phone[1]) {
/* Grab a free ISDN-Channel */ /* Grab a free ISDN-Channel */
if ((chi = if ((chi =
isdn_get_free_slot( isdn_get_free_slot(
...@@ -2327,10 +2322,6 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) ...@@ -2327,10 +2322,6 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
/* Initiate dialing by returning 2 or 4 */ /* Initiate dialing by returning 2 or 4 */
restore_flags(flags); restore_flags(flags);
return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4; return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4;
} else
printk(KERN_WARNING "isdn_net: %s: No phone number\n", lp->name);
restore_flags(flags);
return 0;
} else { } else {
printk(KERN_DEBUG "%s: call from %s -> %s accepted\n", lp->name, nr, printk(KERN_DEBUG "%s: call from %s -> %s accepted\n", lp->name, nr,
eaz); eaz);
...@@ -2381,7 +2372,6 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) ...@@ -2381,7 +2372,6 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
} }
} }
} }
}
/* 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, slot, eaz); printk(KERN_INFO "isdn_net: call from %s -> %d %s ignored\n", nr, slot, eaz);
...@@ -2413,23 +2403,19 @@ isdn_net_findif(char *name) ...@@ -2413,23 +2403,19 @@ 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 == ST_NULL) {
int chi; int chi;
if (lp->phone[1]) { unsigned long flags;
ulong flags;
if (lp->flags & ISDN_NET_CONNECTED || lp->dialstate != ST_NULL)
return -EBUSY;
save_flags(flags); save_flags(flags);
cli(); cli();
/* Grab a free ISDN-Channel */ /* Grab a free ISDN-Channel */
if ((chi = chi = isdn_get_free_slot(ISDN_USAGE_NET, lp->l2_proto, lp->l3_proto,
isdn_get_free_slot( lp->pre_device, lp->pre_channel, lp->msn);
ISDN_USAGE_NET, if (chi < 0) {
lp->l2_proto,
lp->l3_proto,
lp->pre_device,
lp->pre_channel,
lp->msn)
) < 0) {
printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", lp->name); printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", lp->name);
restore_flags(flags); restore_flags(flags);
return -EAGAIN; return -EAGAIN;
...@@ -2447,11 +2433,8 @@ isdn_net_force_dial_lp(isdn_net_local * lp) ...@@ -2447,11 +2433,8 @@ isdn_net_force_dial_lp(isdn_net_local * lp)
/* Initiate dialing */ /* Initiate dialing */
restore_flags(flags); restore_flags(flags);
init_dialout(lp); init_dialout(lp);
return 0; return 0;
} else
return -EINVAL;
} else
return -EBUSY;
} }
/* /*
...@@ -2916,9 +2899,7 @@ isdn_net_addphone(isdn_net_ioctl_phone * phone) ...@@ -2916,9 +2899,7 @@ isdn_net_addphone(isdn_net_ioctl_phone * phone)
return -ENOMEM; return -ENOMEM;
strcpy(n->num, phone->phone); strcpy(n->num, phone->phone);
n->next = p->local.phone[phone->outgoing & 1]; list_add_tail(&n->list, &p->local.phone[phone->outgoing & 1]);
p->local.phone[phone->outgoing & 1] = n;
return 0; return 0;
} }
...@@ -2937,10 +2918,12 @@ isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones) ...@@ -2937,10 +2918,12 @@ 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) { list_for_each_entry(n, &p->local.phone[inout], list) {
if (more) { if (more) {
put_user(' ', phones++); if (put_user(' ', phones++))
return -EFAULT;
count++; count++;
} }
if (copy_to_user(phones, n->num, strlen(n->num) + 1)) { if (copy_to_user(phones, n->num, strlen(n->num) + 1)) {
...@@ -2950,7 +2933,9 @@ isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones) ...@@ -2950,7 +2933,9 @@ isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones)
count += strlen(n->num); count += strlen(n->num);
more = 1; more = 1;
} }
put_user(0, phones); if (put_user(0, phones))
return -EFAULT;
count++; count++;
return count; return count;
} }
...@@ -2989,7 +2974,7 @@ isdn_net_delphone(isdn_net_ioctl_phone * phone) ...@@ -2989,7 +2974,7 @@ isdn_net_delphone(isdn_net_ioctl_phone * phone)
{ {
isdn_net_dev *p = isdn_net_findif(phone->name); isdn_net_dev *p = isdn_net_findif(phone->name);
int inout = phone->outgoing & 1; int inout = phone->outgoing & 1;
struct isdn_net_phone *n, *m; struct isdn_net_phone *n;
unsigned long flags; unsigned long flags;
if (!p) if (!p)
...@@ -2997,22 +2982,13 @@ isdn_net_delphone(isdn_net_ioctl_phone * phone) ...@@ -2997,22 +2982,13 @@ isdn_net_delphone(isdn_net_ioctl_phone * phone)
save_flags(flags); save_flags(flags);
cli(); cli();
n = p->local.phone[inout]; list_for_each_entry(n, &p->local.phone[inout], list) {
m = NULL;
while (n) {
if (!strcmp(n->num, phone->phone)) { if (!strcmp(n->num, phone->phone)) {
if (p->local.dial == n) list_del(&n->list);
p->local.dial = n->next;
if (m)
m->next = n->next;
else
p->local.phone[inout] = n->next;
kfree(n); kfree(n);
restore_flags(flags); restore_flags(flags);
return 0; return 0;
} }
m = n;
n = n->next;
} }
restore_flags(flags); restore_flags(flags);
return -EINVAL; return -EINVAL;
...@@ -3024,22 +3000,20 @@ isdn_net_delphone(isdn_net_ioctl_phone * phone) ...@@ -3024,22 +3000,20 @@ isdn_net_delphone(isdn_net_ioctl_phone * phone)
static int static int
isdn_net_rmallphone(isdn_net_dev * p) isdn_net_rmallphone(isdn_net_dev * p)
{ {
struct isdn_net_phone *n, *m; struct isdn_net_phone *n;
unsigned long flags; unsigned long flags;
int i; int i;
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]; while (!list_empty(&p->local.phone[i])) {
while (n) { n = list_entry(p->local.phone[i].next, struct isdn_net_phone, list);
m = n->next; list_del(&n->list);
kfree(n); kfree(n);
n = m;
} }
p->local.phone[i] = NULL;
} }
p->local.dial = NULL; p->local.dial = 0;
restore_flags(flags); restore_flags(flags);
return 0; return 0;
} }
......
...@@ -413,8 +413,6 @@ get_arg(void *b, void *val, int len) ...@@ -413,8 +413,6 @@ get_arg(void *b, void *val, int len)
static int static int
set_arg(void *b, void *val,int len) set_arg(void *b, void *val,int len)
{ {
if(len <= 0)
len = sizeof(void *);
if (copy_to_user(b, (void *) val, len)) if (copy_to_user(b, (void *) val, len))
return -EFAULT; return -EFAULT;
return 0; return 0;
...@@ -560,13 +558,18 @@ isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned ...@@ -560,13 +558,18 @@ isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned
return isdn_ppp_set_compressor(is, &data); return isdn_ppp_set_compressor(is, &data);
case PPPIOCGCALLINFO: case PPPIOCGCALLINFO:
{ {
struct isdn_net_phone *phone;
struct pppcallinfo pci; struct pppcallinfo pci;
int i;
memset((char *) &pci,0,sizeof(struct pppcallinfo)); memset((char *) &pci,0,sizeof(struct pppcallinfo));
if(lp) if(lp) {
{
strncpy(pci.local_num,lp->msn,63); strncpy(pci.local_num,lp->msn,63);
if(lp->dial) { i = 0;
strncpy(pci.remote_num,lp->dial->num,63); list_for_each_entry(phone, &lp->phone[1], list) {
if (i++ == lp->dial) {
strncpy(pci.remote_num,phone->num,63);
break;
}
} }
pci.charge_units = lp->charge; pci.charge_units = lp->charge;
if(lp->outgoing) if(lp->outgoing)
......
...@@ -266,7 +266,7 @@ typedef struct { ...@@ -266,7 +266,7 @@ typedef struct {
/* Phone-list-element */ /* Phone-list-element */
struct isdn_net_phone { struct isdn_net_phone {
struct isdn_net_phone *next; struct list_head list;
char num[ISDN_MSNLEN]; char num[ISDN_MSNLEN];
}; };
...@@ -334,10 +334,10 @@ typedef struct isdn_net_local_s { ...@@ -334,10 +334,10 @@ typedef struct isdn_net_local_s {
ulong sqfull_stamp; /* Start-Time of overload */ ulong sqfull_stamp; /* Start-Time of overload */
ulong slavedelay; /* Dynamic bundling delaytime */ ulong slavedelay; /* Dynamic bundling delaytime */
int triggercps; /* BogoCPS needed for trigger slave */ int triggercps; /* BogoCPS needed for trigger slave */
struct isdn_net_phone *phone[2]; /* List of remote-phonenumbers */ struct list_head phone[2]; /* List of remote-phonenumbers */
/* phone[0] = Incoming Numbers */ /* phone[0] = Incoming Numbers */
/* phone[1] = Outgoing Numbers */ /* phone[1] = Outgoing Numbers */
struct isdn_net_phone *dial; /* Pointer to dialed number */ int dial; /* # of phone number just dialed */
struct net_device *master; /* Ptr to Master device for slaves */ struct net_device *master; /* Ptr to Master device for slaves */
struct net_device *slave; /* Ptr to Slave device for masters */ struct net_device *slave; /* Ptr to Slave device for masters */
struct isdn_net_local_s *next; /* Ptr to next link in bundle */ struct isdn_net_local_s *next; /* Ptr to next link in bundle */
......
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