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