From cf2e99d6d68576856b36c29f48b05428ea0d7963 Mon Sep 17 00:00:00 2001 From: Kai Germaschewski Date: Sat, 21 Sep 2002 00:09:19 -0500 Subject: ISDN: per-interface hangup timer After the preparation, switching to a per-interface timer is now trivial. --- include/linux/isdn.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/isdn.h b/include/linux/isdn.h index 213d2cbc24f4..174dee960a20 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -285,9 +285,10 @@ typedef struct { typedef struct isdn_net_local_s { ulong magic; char name[10]; /* Name of device */ - struct timer_list dial_timer; /* dial timeout */ + struct timer_list dial_timer; /* dial events timer */ int dial_event; /* event in case of timer expiry */ struct net_device_stats stats; /* Ethernet Statistics */ + struct timer_list hup_timer; /* auto hangup timer */ int isdn_slot; /* Index to isdn device/channel */ int ppp_slot; /* PPPD device slot number */ int pre_device; /* Preselected isdn-device */ -- cgit v1.2.3 From 2a002db29abb87fec80e12395817eadf9d61cd3c Mon Sep 17 00:00:00 2001 From: Kai Germaschewski Date: Sun, 22 Sep 2002 11:13:50 -0500 Subject: ISDN: Kill isdn_net_autohup() It's not used for the timeout controlled hangup anymore, only to hangup depending on the dialmode, which we handle directly now. --- drivers/isdn/i4l/isdn_common.c | 8 ++++---- drivers/isdn/i4l/isdn_net.c | 34 ++++++++++++++-------------------- drivers/isdn/i4l/isdn_net.h | 2 +- include/linux/isdn.h | 4 +--- 4 files changed, 20 insertions(+), 28 deletions(-) (limited to 'include/linux') diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index 528e9d1bf6c4..7012bb414fba 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -264,8 +264,6 @@ isdn_timer_funct(ulong dummy) if (tf & ISDN_TIMER_SLOW) { if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) { isdn_timer_cnt2 = 0; - if (tf & ISDN_TIMER_NETHANGUP) - isdn_net_autohup(); if (++isdn_timer_cnt3 >= ISDN_TIMER_RINGING) { isdn_timer_cnt3 = 0; if (tf & ISDN_TIMER_MODEMRING) @@ -1397,10 +1395,12 @@ isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose); return 0; case IIOCSETGST: - if (arg) + if (arg) { dev->global_flags |= ISDN_GLOBAL_STOPPED; - else + isdn_net_hangup_all(); + } else { dev->global_flags &= ~ISDN_GLOBAL_STOPPED; + } printk(KERN_INFO "isdn: Global Mode %s\n", (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running"); return 0; diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index e690a693834e..4491a67c0285 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -406,23 +406,6 @@ static void isdn_net_hup_timer(unsigned long data) mod_timer(&lp->hup_timer, lp->hup_timer.expires + HZ); } -void -isdn_net_autohup() -{ - struct list_head *l; - - list_for_each(l, &isdn_net_devs) { - isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list); - isdn_net_local *l = &p->local; - - if(dev->global_flags & ISDN_GLOBAL_STOPPED || - ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_OFF) { - isdn_net_hangup(l); - continue; - } - } -} - static void isdn_net_lp_disconnected(isdn_net_local *lp) { isdn_net_rm_from_bundle(lp); @@ -864,6 +847,17 @@ isdn_net_hangup(isdn_net_local *lp) isdn_net_unbind_channel(lp); } +void +isdn_net_hangup_all() +{ + struct list_head *l; + + list_for_each(l, &isdn_net_devs) { + isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list); + isdn_net_hangup(&p->local); + } +} + typedef struct { unsigned short source; unsigned short dest; @@ -2842,6 +2836,9 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) else { lp->flags |= cfg->dialmode; /* turn on selected bits */ } + if (lp->flags & ISDN_NET_DM_OFF) + isdn_net_hangup(lp); + if (cfg->chargehup) lp->hupflags |= ISDN_CHARGEHUP; else @@ -3151,9 +3148,6 @@ isdn_net_realrm(isdn_net_dev *p) } } } - /* If no more net-devices remain, disable auto-hangup timer */ - if (list_empty(&isdn_net_devs)) - isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0); restore_flags(flags); kfree(p); diff --git a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h index a61de86b7bc2..1d25e2a23d3a 100644 --- a/drivers/isdn/i4l/isdn_net.h +++ b/drivers/isdn/i4l/isdn_net.h @@ -42,7 +42,7 @@ extern int isdn_net_getpeer(isdn_net_ioctl_phone *, isdn_net_ioctl_phone *); extern int isdn_net_delphone(isdn_net_ioctl_phone *); extern int isdn_net_find_icall(int, int, int, setup_parm *); extern void isdn_net_hangup(isdn_net_local *); -extern void isdn_net_autohup(void); +extern void isdn_net_hangup_all(void); extern int isdn_net_force_hangup(char *); extern int isdn_net_force_dial(char *); extern isdn_net_dev *isdn_net_findif(char *); diff --git a/include/linux/isdn.h b/include/linux/isdn.h index 174dee960a20..d5907b2cd5bc 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -245,12 +245,10 @@ typedef struct { #define ISDN_TIMER_MODEMPLUS 2 #define ISDN_TIMER_MODEMRING 4 #define ISDN_TIMER_MODEMXMIT 8 -#define ISDN_TIMER_NETHANGUP 32 #define ISDN_TIMER_CARRIER 256 /* Wait for Carrier */ #define ISDN_TIMER_FAST (ISDN_TIMER_MODEMREAD | ISDN_TIMER_MODEMPLUS | \ ISDN_TIMER_MODEMXMIT) -#define ISDN_TIMER_SLOW (ISDN_TIMER_MODEMRING | ISDN_TIMER_NETHANGUP | \ - ISDN_TIMER_CARRIER) +#define ISDN_TIMER_SLOW (ISDN_TIMER_MODEMRING | ISDN_TIMER_CARRIER) /* GLOBAL_FLAGS */ #define ISDN_GLOBAL_STOPPED 1 -- cgit v1.2.3 From 7e22da6ad5281a47cda7d2644410188c2debb838 Mon Sep 17 00:00:00 2001 From: Kai Germaschewski Date: Sun, 22 Sep 2002 11:55:15 -0500 Subject: ISDN: ISDN_GLOBAL_STOPPED cleanup ISDN_GLOBAL_STOPPED is a way to globally stop the system from dialing out / accepting incoming calls. Instead of spreading checks all over the place, just catch dial commands / incoming call indications in one place. Also, kill isdn_net_phone typedef and clean up affected code. --- drivers/isdn/i4l/isdn_common.c | 32 ++----- drivers/isdn/i4l/isdn_net.c | 206 +++++++++++++++++------------------------ include/linux/isdn.h | 12 +-- 3 files changed, 102 insertions(+), 148 deletions(-) (limited to 'include/linux') diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index 7012bb414fba..479354a90855 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -449,8 +449,6 @@ isdn_status_callback(isdn_ctrl * c) case ISDN_STAT_BSENT: if (i < 0) return -1; - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; if (isdn_net_stat_callback(i, c)) return 0; if (isdn_v110_stat_callback(&slot[i].iv110, c)) @@ -480,15 +478,11 @@ isdn_status_callback(isdn_ctrl * c) if (i < 0) return -1; dbg_statcallb("ICALL: %d (%d,%ld) %s\n", i, di, c->arg, c->parm.num); - if (dev->global_flags & ISDN_GLOBAL_STOPPED) { - cmd.driver = di; - cmd.arg = c->arg; - cmd.command = ISDN_CMD_HANGUP; - isdn_command(&cmd); + if (dev->global_flags & ISDN_GLOBAL_STOPPED) return 0; - } + /* Try to find a network-interface which will accept incoming call */ - r = ((c->command == ISDN_STAT_ICALLW) ? 0 : isdn_net_find_icall(di, c->arg, i, &c->parm.setup)); + r = isdn_net_find_icall(di, c->arg, i, &c->parm.setup); switch (r) { case 0: /* No network-device replies. @@ -548,8 +542,6 @@ isdn_status_callback(isdn_ctrl * c) if (i < 0) return -1; dbg_statcallb("CINF: %d %s\n", i, c->parm.num); - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; if (strcmp(c->parm.num, "0")) isdn_net_stat_callback(i, c); isdn_tty_stat_callback(i, c); @@ -572,8 +564,6 @@ isdn_status_callback(isdn_ctrl * c) if (i < 0) return -1; dbg_statcallb("DCONN: %d\n", i); - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; /* Find any net-device, waiting for D-channel setup */ if (isdn_net_stat_callback(i, c)) break; @@ -591,8 +581,6 @@ isdn_status_callback(isdn_ctrl * c) if (i < 0) return -1; dbg_statcallb("DHUP: %d\n", i); - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; dev->drv[di]->online &= ~(1 << (c->arg)); isdn_info_update(); /* Signal hangup to network-devices */ @@ -609,8 +597,6 @@ isdn_status_callback(isdn_ctrl * c) return -1; dbg_statcallb("BCONN: %ld\n", c->arg); /* Signal B-channel-connect to network-devices */ - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; dev->drv[di]->online |= (1 << (c->arg)); isdn_info_update(); if (isdn_net_stat_callback(i, c)) @@ -623,8 +609,6 @@ isdn_status_callback(isdn_ctrl * c) if (i < 0) return -1; dbg_statcallb("BHUP: %d\n", i); - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; dev->drv[di]->online &= ~(1 << (c->arg)); isdn_info_update(); #ifdef CONFIG_ISDN_X25 @@ -640,8 +624,6 @@ isdn_status_callback(isdn_ctrl * c) if (i < 0) return -1; dbg_statcallb("NODCH: %ld\n", c->arg); - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; if (isdn_net_stat_callback(i, c)) break; if (isdn_tty_stat_callback(i, c)) @@ -1401,8 +1383,6 @@ isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) } else { dev->global_flags &= ~ISDN_GLOBAL_STOPPED; } - printk(KERN_INFO "isdn: Global Mode %s\n", - (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running"); return 0; case IIOCSETBRJ: drvidx = -1; @@ -2119,14 +2099,20 @@ isdn_slot_map_eaz2msn(int sl, char *msn) 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; + case ISDN_CMD_DIAL: + if (dev->global_flags & ISDN_GLOBAL_STOPPED) + return -EBUSY; + /* fall through */ default: ctrl->arg = isdn_slot_channel(sl); break; diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 4491a67c0285..76d075af11e2 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -206,7 +206,7 @@ static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp) int isdn_net_force_dial_lp(isdn_net_local *); static int isdn_net_start_xmit(struct sk_buff *, struct net_device *); -static int do_dialout(isdn_net_local *lp); +static void do_dialout(isdn_net_local *lp); static void isdn_net_ciscohdlck_connected(isdn_net_local *lp); static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp); @@ -222,22 +222,14 @@ char *isdn_net_revision = "$Revision: 1.140.6.11 $"; static void isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason) { - if(skb) { - - u_short proto = ntohs(skb->protocol); - - printk(KERN_DEBUG "isdn_net: %s: %s, signalling dst_link_failure %s\n", - dev->name, - (reason != NULL) ? reason : "unknown", - (proto != ETH_P_IP) ? "Protocol != ETH_P_IP" : ""); - - dst_link_failure(skb); - } - else { /* dial not triggered by rawIP packet */ - printk(KERN_DEBUG "isdn_net: %s: %s\n", - dev->name, - (reason != NULL) ? reason : "reason unknown"); - } + u_short proto = ntohs(skb->protocol); + + printk(KERN_DEBUG "isdn_net: %s: %s, signalling dst_link_failure %s\n", + dev->name, + (reason != NULL) ? reason : "unknown", + (proto != ETH_P_IP) ? "Protocol != ETH_P_IP" : ""); + + dst_link_failure(skb); } static void @@ -491,7 +483,7 @@ isdn_net_dial_timer(unsigned long data) /* Initiate dialout. Set phone-number-pointer to first number * of interface. */ -static int +static void init_dialout(isdn_net_local *lp) { unsigned long flags; @@ -505,7 +497,7 @@ init_dialout(isdn_net_local *lp) printk(KERN_WARNING "%s: phone number deleted?\n", lp->name); isdn_net_hangup(lp); - return 0; + return; } if (lp->dialtimeout > 0 && (lp->dialstarted == 0 || @@ -514,83 +506,59 @@ init_dialout(isdn_net_local *lp) lp->dialwait_timer = 0; } lp->dialretry = 0; - return do_dialout(lp); + do_dialout(lp); } /* Setup interface, dial current phone-number, switch to next number. * If list of phone-numbers is exhausted, increment * retry-counter. */ -static int +static void do_dialout(isdn_net_local *lp) { unsigned long flags; - - if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF)) { - char *s; - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - s = "dial suppressed: isdn system stopped"; - else - s = "dial suppressed: dialmode `off'"; - isdn_net_unreachable(&lp->netdev->dev, 0, s); - isdn_net_hangup(lp); - return 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 (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) + return; save_flags(flags); cli(); - if (!lp->dial) { - restore_flags(flags); - printk(KERN_WARNING "%s: phone number deleted?\n", - lp->name); - isdn_net_hangup(lp); - return 0; + 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; } - if (!strncmp(lp->dial->num, "LEASED", strlen("LEASED"))) { - restore_flags(flags); - lp->dialstate = ST_OUT_WAIT_DCONN; - printk(KERN_INFO "%s: Open leased line ...\n", lp->name); - return 1; - } else { - struct dial_info dial = { - .l2_proto = lp->l2_proto, - .l3_proto = lp->l3_proto, - .si1 = 7, - .si2 = 0, - .msn = lp->msn, - .phone = lp->dial->num, - }; - if(lp->dialtimeout > 0) { - if (time_after(jiffies, lp->dialstarted + lp->dialtimeout)) { - restore_flags(flags); + /* + * Switch to next number or back to start if at end of list. + */ + if (!(lp->dial = lp->dial->next)) { + lp->dial = lp->phone[1]; + lp->dialretry++; + + if (lp->dialretry > lp->dialmax) { + restore_flags(flags); + if (lp->dialtimeout == 0) { lp->dialwait_timer = jiffies + lp->dialwait; lp->dialstarted = 0; - isdn_net_unreachable(&lp->netdev->dev, 0, "dial: timed out"); - isdn_net_hangup(lp); - return 0; - } - } - /* - * Switch to next number or back to start if at end of list. - */ - if (!(lp->dial = (isdn_net_phone *) lp->dial->next)) { - lp->dial = lp->phone[1]; - lp->dialretry++; - - if (lp->dialretry > lp->dialmax) { - restore_flags(flags); - if (lp->dialtimeout == 0) { - lp->dialwait_timer = jiffies + lp->dialwait; - lp->dialstarted = 0; - isdn_net_unreachable(&lp->netdev->dev, 0, "dial: tried all numbers dialmax times"); - } - isdn_net_hangup(lp); - return 0; } + isdn_net_hangup(lp); + return; } - restore_flags(flags); - isdn_slot_dial(lp->isdn_slot, &dial); } + restore_flags(flags); + isdn_slot_dial(lp->isdn_slot, &dial); + lp->huptimer = 0; lp->outgoing = 1; if (lp->chargeint) @@ -607,7 +575,6 @@ do_dialout(isdn_net_local *lp) } lp->dialstate = ST_OUT_WAIT_DCONN; add_timer(&lp->dial_timer); - return 1; } /* For EV_NET_DIAL, returns 1 if timer callback is needed @@ -2114,7 +2081,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) int swapped; int sidx = 0; struct list_head *l; - isdn_net_phone *n; + struct isdn_net_phone *n; ulong flags; char nr[32]; char *my_eaz; @@ -2148,7 +2115,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) return 0; } - n = (isdn_net_phone *) 0; + n = NULL; ematch = wret = swapped = 0; dbg_net_icall("n_fi: di=%d ch=%d idx=%d usg=%d\n", di, ch, idx, isdn_slot_usage(idx)); @@ -2259,7 +2226,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) while (n) { if (!isdn_msncmp(nr, n->num)) break; - n = (isdn_net_phone *) n->next; + n = n->next; } } if (n || (!(lp->flags & ISDN_NET_SECURE))) { @@ -2939,17 +2906,20 @@ int isdn_net_addphone(isdn_net_ioctl_phone * phone) { isdn_net_dev *p = isdn_net_findif(phone->name); - isdn_net_phone *n; + struct isdn_net_phone *n; - if (p) { - if (!(n = (isdn_net_phone *) kmalloc(sizeof(isdn_net_phone), GFP_KERNEL))) - return -ENOMEM; - strcpy(n->num, phone->phone); - n->next = p->local.phone[phone->outgoing & 1]; - p->local.phone[phone->outgoing & 1] = n; - return 0; - } - return -ENODEV; + if (!p) + return -ENODEV; + + n = kmalloc(sizeof(*n), GFP_KERNEL); + if (!n) + return -ENOMEM; + + strcpy(n->num, phone->phone); + n->next = p->local.phone[phone->outgoing & 1]; + p->local.phone[phone->outgoing & 1] = n; + + return 0; } /* @@ -2963,7 +2933,7 @@ isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones) int inout = phone->outgoing & 1; int more = 0; int count = 0; - isdn_net_phone *n; + struct isdn_net_phone *n; if (!p) return -ENODEV; @@ -3019,34 +2989,33 @@ isdn_net_delphone(isdn_net_ioctl_phone * phone) { isdn_net_dev *p = isdn_net_findif(phone->name); int inout = phone->outgoing & 1; - isdn_net_phone *n; - isdn_net_phone *m; + struct isdn_net_phone *n, *m; unsigned long flags; - if (p) { - save_flags(flags); - cli(); - n = p->local.phone[inout]; - m = NULL; - while (n) { - if (!strcmp(n->num, phone->phone)) { - if (p->local.dial == n) - p->local.dial = n->next; - if (m) - m->next = n->next; - else - p->local.phone[inout] = n->next; - kfree(n); - restore_flags(flags); - return 0; - } - m = n; - n = (isdn_net_phone *) n->next; + if (!p) + return -ENODEV; + + save_flags(flags); + cli(); + n = p->local.phone[inout]; + m = NULL; + while (n) { + if (!strcmp(n->num, phone->phone)) { + if (p->local.dial == n) + p->local.dial = n->next; + if (m) + m->next = n->next; + else + p->local.phone[inout] = n->next; + kfree(n); + restore_flags(flags); + return 0; } - restore_flags(flags); - return -EINVAL; + m = n; + n = n->next; } - return -ENODEV; + restore_flags(flags); + return -EINVAL; } /* @@ -3055,8 +3024,7 @@ isdn_net_delphone(isdn_net_ioctl_phone * phone) static int isdn_net_rmallphone(isdn_net_dev * p) { - isdn_net_phone *n; - isdn_net_phone *m; + struct isdn_net_phone *n, *m; unsigned long flags; int i; diff --git a/include/linux/isdn.h b/include/linux/isdn.h index d5907b2cd5bc..f1f305fe3954 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -265,10 +265,10 @@ typedef struct { #define ISDN_NET_MAGIC 0x49344C02 /* for paranoia-checking */ /* Phone-list-element */ -typedef struct { - void *next; - char num[ISDN_MSNLEN]; -} isdn_net_phone; +struct isdn_net_phone { + struct isdn_net_phone *next; + char num[ISDN_MSNLEN]; +}; /* Principles when extending structures for generic encapsulation protocol @@ -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 */ - isdn_net_phone *phone[2]; /* List of remote-phonenumbers */ + struct isdn_net_phone *phone[2]; /* List of remote-phonenumbers */ /* phone[0] = Incoming Numbers */ /* phone[1] = Outgoing Numbers */ - isdn_net_phone *dial; /* Pointer to dialed number */ + struct isdn_net_phone *dial; /* Pointer to dialed number */ 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 */ -- cgit v1.2.3 From 51430a3c38c53aeb8d8c4d81a214b54da0eb6d19 Mon Sep 17 00:00:00 2001 From: Kai Germaschewski Date: Sun, 22 Sep 2002 12:46:11 -0500 Subject: ISDN: Use 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. --- drivers/isdn/i4l/isdn_net.c | 552 +++++++++++++++++++++----------------------- drivers/isdn/i4l/isdn_ppp.c | 15 +- include/linux/isdn.h | 6 +- 3 files changed, 275 insertions(+), 298 deletions(-) (limited to 'include/linux') diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 76d075af11e2..89992cb8a6fc 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -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,24 +510,48 @@ 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; + + if (list_empty(&lp->phone[1])) + return; + + i = 0; + list_for_each_entry(phone, &lp->phone[1], list) { + if (i++ == lp->dial) + goto found; + } + /* 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) { + if (lp->dialtimeout == 0) { + lp->dialwait_timer = jiffies + lp->dialwait; + lp->dialstarted = 0; + } + isdn_net_hangup(lp); + return; + } + + found: + lp->dial++; + dial.phone = phone->num; - 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); @@ -542,21 +560,6 @@ do_dialout(isdn_net_local *lp) /* * Switch to next number or back to start if at end of list. */ - if (!(lp->dial = lp->dial->next)) { - lp->dial = lp->phone[1]; - lp->dialretry++; - - if (lp->dialretry > lp->dialmax) { - restore_flags(flags); - if (lp->dialtimeout == 0) { - lp->dialwait_timer = jiffies + lp->dialwait; - lp->dialstarted = 0; - } - isdn_net_hangup(lp); - return; - } - } - restore_flags(flags); 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,80 +1175,73 @@ 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(); - - if(lp->dialwait_timer <= 0) - if(lp->dialstarted > 0 && lp->dialtimeout > 0 && time_before(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait)) - lp->dialwait_timer = lp->dialstarted + lp->dialtimeout + lp->dialwait; - - if(lp->dialwait_timer > 0) { - if(time_before(jiffies, lp->dialwait_timer)) { - isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached"); - dev_kfree_skb(skb); - restore_flags(flags); - return 0; - } else - lp->dialwait_timer = 0; - } - /* 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^1, - lp->msn) - ) < 0)) { - restore_flags(flags); - isdn_net_unreachable(ndev, skb, - "No channel"); + + save_flags(flags); + cli(); + + if(lp->dialwait_timer <= 0) + if(lp->dialstarted > 0 && lp->dialtimeout > 0 && time_before(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait)) + lp->dialwait_timer = lp->dialstarted + lp->dialtimeout + lp->dialwait; + + if(lp->dialwait_timer > 0) { + if(time_before(jiffies, lp->dialwait_timer)) { + isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached"); dev_kfree_skb(skb); + restore_flags(flags); return 0; - } - /* Log packet, which triggered dialing */ - if (dev->net_verbose) - isdn_net_log_skb(skb, lp); - /* Connect interface with channel */ - isdn_net_bind_channel(lp, chi); + } else + lp->dialwait_timer = 0; + } + /* 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^1, + lp->msn) + ) < 0)) { + restore_flags(flags); + isdn_net_unreachable(ndev, skb, + "No channel"); + dev_kfree_skb(skb); + return 0; + } + /* Log packet, which triggered dialing */ + if (dev->net_verbose) + isdn_net_log_skb(skb, lp); + /* Connect interface with channel */ + isdn_net_bind_channel(lp, chi); #ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) { - /* no 'first_skb' handling for syncPPP */ - if (isdn_ppp_bind(lp) < 0) { - dev_kfree_skb(skb); - isdn_net_unbind_channel(lp); - restore_flags(flags); - return 0; /* STN (skb to nirvana) ;) */ - } + if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) { + /* no 'first_skb' handling for syncPPP */ + if (isdn_ppp_bind(lp) < 0) { + dev_kfree_skb(skb); + isdn_net_unbind_channel(lp); restore_flags(flags); - init_dialout(lp); - netif_stop_queue(ndev); - return 1; /* let upper layer requeue skb packet */ + return 0; /* STN (skb to nirvana) ;) */ } -#endif - /* Initiate dialing */ restore_flags(flags); 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; + netif_stop_queue(ndev); + return 1; /* let upper layer requeue skb packet */ } +#endif + /* Initiate dialing */ + restore_flags(flags); + init_dialout(lp); + isdn_net_device_stop_queue(lp); + return 1; } else { /* Device is connected to an ISDN channel */ ndev->trans_start = jiffies; @@ -2221,166 +2218,159 @@ 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 */ + dbg_net_icall("n_fi: match3\n"); + /* matching interface found */ + /* + * Is the state STOPPED? + * If so, no dialin is allowed, + * so reject actively. + * */ + if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) { + restore_flags(flags); + printk(KERN_INFO "incoming call, interface %s `stopped' -> rejected\n", + lp->name); + return 3; + } + /* + * Is the interface up? + * If not, reject the call actively. + */ + if (!isdn_net_device_started(p)) { + restore_flags(flags); + printk(KERN_INFO "%s: incoming call, interface down -> rejected\n", + lp->name); + return 3; + } + /* Interface is up, now see if it's a slave. If so, see if + * it's master and parent slave is online. If not, reject the call. + */ + if (lp->master) { + isdn_net_local *mlp = (isdn_net_local *) lp->master->priv; + printk(KERN_DEBUG "ICALLslv: %s\n", lp->name); + printk(KERN_DEBUG "master=%s\n", mlp->name); + if (mlp->flags & ISDN_NET_CONNECTED) { + printk(KERN_DEBUG "master online\n"); + /* Master is online, find parent-slave (master if first slave) */ + while (mlp->slave) { + if ((isdn_net_local *) mlp->slave->priv == lp) + break; + mlp = (isdn_net_local *) mlp->slave->priv; + } + } else + printk(KERN_DEBUG "master offline\n"); + /* Found parent, if it's offline iterate next device */ + printk(KERN_DEBUG "mlpf: %d\n", mlp->flags & ISDN_NET_CONNECTED); + if (!(mlp->flags & ISDN_NET_CONNECTED)) { + continue; + } + } + if (lp->flags & ISDN_NET_CALLBACK) { + int chi; /* - * Is the state STOPPED? - * If so, no dialin is allowed, + * Is the state MANUAL? + * If so, no callback can be made, * so reject actively. * */ if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) { restore_flags(flags); - printk(KERN_INFO "incoming call, interface %s `stopped' -> rejected\n", + printk(KERN_INFO "incoming call for callback, interface %s `off' -> rejected\n", lp->name); return 3; } - /* - * Is the interface up? - * If not, reject the call actively. - */ - if (!isdn_net_device_started(p)) { + printk(KERN_DEBUG "%s: call from %s -> %s, start callback\n", + lp->name, nr, eaz); + + /* 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) { + + printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n", lp->name); restore_flags(flags); - printk(KERN_INFO "%s: incoming call, interface down -> rejected\n", - lp->name); - return 3; + return 0; } - /* Interface is up, now see if it's a slave. If so, see if - * it's master and parent slave is online. If not, reject the call. - */ - if (lp->master) { - isdn_net_local *mlp = (isdn_net_local *) lp->master->priv; - printk(KERN_DEBUG "ICALLslv: %s\n", lp->name); - printk(KERN_DEBUG "master=%s\n", mlp->name); - if (mlp->flags & ISDN_NET_CONNECTED) { - printk(KERN_DEBUG "master online\n"); - /* Master is online, find parent-slave (master if first slave) */ - while (mlp->slave) { - if ((isdn_net_local *) mlp->slave->priv == lp) - break; - mlp = (isdn_net_local *) mlp->slave->priv; - } - } else - printk(KERN_DEBUG "master offline\n"); - /* Found parent, if it's offline iterate next device */ - printk(KERN_DEBUG "mlpf: %d\n", mlp->flags & ISDN_NET_CONNECTED); - if (!(mlp->flags & ISDN_NET_CONNECTED)) { - continue; - } - } - if (lp->flags & ISDN_NET_CALLBACK) { - int chi; - /* - * Is the state MANUAL? - * If so, no callback can be made, - * so reject actively. - * */ - if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) { - restore_flags(flags); - printk(KERN_INFO "incoming call for callback, interface %s `off' -> rejected\n", - lp->name); - return 3; - } - 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( - ISDN_USAGE_NET, - lp->l2_proto, - lp->l3_proto, - lp->pre_device, - lp->pre_channel, - lp->msn) - ) < 0) { - - printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n", lp->name); - restore_flags(flags); - return 0; - } - /* Setup dialstate. */ - lp->dial_timer.expires = jiffies + lp->cbdelay; - lp->dial_event = EV_NET_TIMER_CB; - add_timer(&lp->dial_timer); - - lp->dialstate = ST_WAIT_BEFORE_CB; - /* Connect interface with channel */ - isdn_net_bind_channel(lp, chi); + /* Setup dialstate. */ + lp->dial_timer.expires = jiffies + lp->cbdelay; + lp->dial_event = EV_NET_TIMER_CB; + add_timer(&lp->dial_timer); + + lp->dialstate = ST_WAIT_BEFORE_CB; + /* Connect interface with channel */ + isdn_net_bind_channel(lp, chi); #ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) - if (isdn_ppp_bind(lp) < 0) { - isdn_net_unbind_channel(lp); - restore_flags(flags); - return 0; - } -#endif - /* Initiate dialing by returning 2 or 4 */ + if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) + if (isdn_ppp_bind(lp) < 0) { + isdn_net_unbind_channel(lp); 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); - /* if this interface is dialing, it does it probably on a different - device, so free this device */ - if (lp->dialstate == ST_OUT_WAIT_DCONN) { -#ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) - isdn_ppp_free(lp); -#endif - isdn_net_lp_disconnected(lp); - isdn_slot_free(lp->isdn_slot, - ISDN_USAGE_NET); + return 0; } - strcpy(isdn_slot_num(idx), nr); - isdn_slot_set_usage(idx, (isdn_slot_usage(idx) & ISDN_USAGE_EXCLUSIVE) | ISDN_USAGE_NET); - isdn_slot_set_st_netdev(idx, lp->netdev); - lp->isdn_slot = slot; - lp->ppp_slot = -1; - lp->flags |= ISDN_NET_CONNECTED; - - lp->outgoing = 0; - lp->huptimer = 0; - lp->charge_state = ST_CHARGE_NULL; - /* 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; - +#endif + /* Initiate dialing by returning 2 or 4 */ + restore_flags(flags); + return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4; + } else { + printk(KERN_DEBUG "%s: call from %s -> %s accepted\n", lp->name, nr, + eaz); + /* if this interface is dialing, it does it probably on a different + device, so free this device */ + if (lp->dialstate == ST_OUT_WAIT_DCONN) { #ifdef CONFIG_ISDN_PPP if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) - if (isdn_ppp_bind(lp) < 0) { - isdn_net_unbind_channel(lp); - restore_flags(flags); - return 0; - } + isdn_ppp_free(lp); #endif - restore_flags(flags); - return 1; + isdn_net_lp_disconnected(lp); + isdn_slot_free(lp->isdn_slot, + ISDN_USAGE_NET); } + strcpy(isdn_slot_num(idx), nr); + isdn_slot_set_usage(idx, (isdn_slot_usage(idx) & ISDN_USAGE_EXCLUSIVE) | ISDN_USAGE_NET); + isdn_slot_set_st_netdev(idx, lp->netdev); + lp->isdn_slot = slot; + lp->ppp_slot = -1; + lp->flags |= ISDN_NET_CONNECTED; + + lp->outgoing = 0; + lp->huptimer = 0; + lp->charge_state = ST_CHARGE_NULL; + /* Got incoming Call, setup L2 and L3 protocols, + * then wait for D-Channel-connect + */ + cmd.arg = lp->l2_proto << 8; + isdn_slot_command(lp->isdn_slot, ISDN_CMD_SETL2, &cmd); + cmd.arg = lp->l3_proto << 8; + isdn_slot_command(lp->isdn_slot, ISDN_CMD_SETL3, &cmd); + + lp->dial_timer.expires = jiffies + 15 * HZ; + lp->dial_event = EV_NET_TIMER_IN_DCONN; + add_timer(&lp->dial_timer); + lp->dialstate = ST_IN_WAIT_DCONN; + +#ifdef CONFIG_ISDN_PPP + if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) + if (isdn_ppp_bind(lp) < 0) { + isdn_net_unbind_channel(lp); + restore_flags(flags); + return 0; + } +#endif + restore_flags(flags); + return 1; } - } + } } /* If none of configured EAZ/MSN matched and not verbose, be silent */ if (!ematch || dev->net_verbose) @@ -2413,45 +2403,38 @@ 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; - save_flags(flags); - cli(); + int chi; + unsigned long flags; - /* 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) { - printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", lp->name); - restore_flags(flags); - return -EAGAIN; - } - /* Connect interface with channel */ - isdn_net_bind_channel(lp, chi); + if (lp->flags & ISDN_NET_CONNECTED || lp->dialstate != ST_NULL) + return -EBUSY; + + save_flags(flags); + cli(); + + /* Grab a free ISDN-Channel */ + 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; + } + /* Connect interface with channel */ + isdn_net_bind_channel(lp, chi); #ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) - if (isdn_ppp_bind(lp) < 0) { - isdn_net_unbind_channel(lp); - restore_flags(flags); - return -EAGAIN; - } -#endif - /* Initiate dialing */ + if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) + if (isdn_ppp_bind(lp) < 0) { + isdn_net_unbind_channel(lp); restore_flags(flags); - init_dialout(lp); - return 0; - } else - return -EINVAL; - } else - return -EBUSY; + return -EAGAIN; + } +#endif + /* Initiate dialing */ + restore_flags(flags); + init_dialout(lp); + + return 0; } /* @@ -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; } diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index 44d865ed4bf1..3918b0ed60a0 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -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) diff --git a/include/linux/isdn.h b/include/linux/isdn.h index f1f305fe3954..d178bf752006 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -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 */ -- cgit v1.2.3 From cd2d00c61c3472b74bf24ac7082eafee35666506 Mon Sep 17 00:00:00 2001 From: Kai Germaschewski Date: Sun, 22 Sep 2002 13:42:42 -0500 Subject: ISDN: Lock list of phone numbers appropriately It was (only partially) protected by cli() before, which we want to get rid of. --- drivers/isdn/i4l/isdn_common.c | 3 +- drivers/isdn/i4l/isdn_net.c | 93 +++++++++++++++++++++++------------------- include/linux/isdn.h | 1 + 3 files changed, 55 insertions(+), 42 deletions(-) (limited to 'include/linux') diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index 479354a90855..d7a133f13af3 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -1599,8 +1599,9 @@ static struct file_operations isdn_ctrl_fops = .release = isdn_ctrl_release, }; + /* - * file_operations for major 43, /dev/isdn* + * file_operations for major 45, /dev/isdn* * stolen from drivers/char/misc.c */ diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 89992cb8a6fc..04158757eef8 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -486,12 +486,7 @@ isdn_net_dial_timer(unsigned long data) static void init_dialout(isdn_net_local *lp) { - unsigned long flags; - - save_flags(flags); - cli(); lp->dial = 0; - restore_flags(flags); if (lp->dialtimeout > 0 && (lp->dialstarted == 0 || @@ -524,9 +519,11 @@ do_dialout(isdn_net_local *lp) if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) 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; - + } i = 0; list_for_each_entry(phone, &lp->phone[1], list) { if (i++ == lp->dial) @@ -537,6 +534,11 @@ do_dialout(isdn_net_local *lp) lp->dial = 0; lp->dialretry++; + found: + lp->dial++; + dial.phone = phone->num; + spin_unlock_irqrestore(&lp->lock, flags); + if (lp->dialretry > lp->dialmax) { if (lp->dialtimeout == 0) { lp->dialwait_timer = jiffies + lp->dialwait; @@ -545,17 +547,12 @@ 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; + lp->dialwait_timer = jiffies + lp->dialwait; + lp->dialstarted = 0; + isdn_net_hangup(lp); + return; } /* * 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) } dbg_net_icall("n_fi: match2\n"); if (lp->flags & ISDN_NET_SECURE) { + spin_lock_irqsave(&lp->lock, flags); 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; + } } + spin_unlock_irqrestore(&lp->lock, flags); continue; } dbg_net_icall("n_fi: match3\n"); @@ -2557,6 +2558,9 @@ isdn_net_new(char *name, struct net_device *master) init_timer(&netdev->local.hup_timer); netdev->local.hup_timer.data = (unsigned long) &netdev->local; 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 */ list_add(&netdev->global_list, &isdn_net_devs); @@ -2889,6 +2893,7 @@ int isdn_net_addphone(isdn_net_ioctl_phone * phone) { isdn_net_dev *p = isdn_net_findif(phone->name); + unsigned long flags; struct isdn_net_phone *n; if (!p) @@ -2899,7 +2904,9 @@ isdn_net_addphone(isdn_net_ioctl_phone * phone) return -ENOMEM; strcpy(n->num, phone->phone); + spin_lock_irqsave(&p->local.lock, flags); list_add_tail(&n->list, &p->local.phone[phone->outgoing & 1]); + spin_unlock_irqrestore(&p->local.lock, flags); return 0; } @@ -2911,32 +2918,37 @@ int isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones) { isdn_net_dev *p = isdn_net_findif(phone->name); + unsigned long flags; int inout = phone->outgoing & 1; - int more = 0; int count = 0; + char *buf = (char *)__get_free_page(GFP_KERNEL); struct isdn_net_phone *n; if (!p) return -ENODEV; + if (!buf) + return -ENOMEM; + inout &= 1; + spin_lock_irqsave(&p->local.lock, flags); list_for_each_entry(n, &p->local.phone[inout], list) { - if (more) { - if (put_user(' ', phones++)) - return -EFAULT; - count++; - } - if (copy_to_user(phones, n->num, strlen(n->num) + 1)) { - return -EFAULT; - } - phones += strlen(n->num); + strcpy(&buf[count], n->num); count += strlen(n->num); - more = 1; + buf[count++] = ' '; + if (count > PAGE_SIZE - ISDN_MSNLEN - 1) + break; } - if (put_user(0, phones)) - return -EFAULT; + spin_unlock_irqrestore(&p->local.lock, flags); + if (!count) + count++; + + buf[count-1] = 0; - count++; + if (copy_to_user(phones, buf, count)) + count = -EFAULT; + + free_page((unsigned long)buf); return count; } @@ -2976,22 +2988,23 @@ isdn_net_delphone(isdn_net_ioctl_phone * phone) int inout = phone->outgoing & 1; struct isdn_net_phone *n; unsigned long flags; + int retval; if (!p) return -ENODEV; - save_flags(flags); - cli(); + retval = -EINVAL; + spin_lock_irqsave(&p->local.lock, flags); list_for_each_entry(n, &p->local.phone[inout], list) { if (!strcmp(n->num, phone->phone)) { list_del(&n->list); kfree(n); - restore_flags(flags); - return 0; + retval = 0; + break; } } - restore_flags(flags); - return -EINVAL; + spin_unlock_irqrestore(&p->local.lock, flags); + return retval; } /* @@ -3004,8 +3017,7 @@ isdn_net_rmallphone(isdn_net_dev * p) unsigned long flags; int i; - save_flags(flags); - cli(); + spin_lock_irqsave(&p->local.lock, flags); for (i = 0; i < 2; i++) { while (!list_empty(&p->local.phone[i])) { n = list_entry(p->local.phone[i].next, struct isdn_net_phone, list); @@ -3013,8 +3025,7 @@ isdn_net_rmallphone(isdn_net_dev * p) kfree(n); } } - p->local.dial = 0; - restore_flags(flags); + spin_lock_irqsave(&p->local.lock, flags); return 0; } diff --git a/include/linux/isdn.h b/include/linux/isdn.h index d178bf752006..ee65c234e121 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -281,6 +281,7 @@ struct isdn_net_phone { /* Local interface-data */ typedef struct isdn_net_local_s { + spinlock_t lock; ulong magic; char name[10]; /* Name of device */ struct timer_list dial_timer; /* dial events timer */ -- cgit v1.2.3 From 767bf8a2a9a3b7cc8fe74d050392dc4d370597fb Mon Sep 17 00:00:00 2001 From: Kai Germaschewski Date: Mon, 23 Sep 2002 01:18:43 -0500 Subject: ISDN: Fix build when CONFIG_ISDN_TTY_FAX is not set T30_s * is part of a union, so the typedef needs to exist even when CONFIG_ISDN_TTY_FAX is not set. --- include/linux/isdnif.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/isdnif.h b/include/linux/isdnif.h index cb025c8e4759..c9718d4de584 100644 --- a/include/linux/isdnif.h +++ b/include/linux/isdnif.h @@ -275,7 +275,6 @@ typedef struct setup_parm { } setup_parm; -#ifdef CONFIG_ISDN_TTY_FAX /* T.30 Fax G3 */ #define FAXIDLEN 21 @@ -350,8 +349,6 @@ typedef struct T30_s { #define ISDN_FAX_PHASE_D 4 #define ISDN_FAX_PHASE_E 5 -#endif /* TTY_FAX */ - #define ISDN_FAX_CLASS1_FAE 0 #define ISDN_FAX_CLASS1_FTS 1 #define ISDN_FAX_CLASS1_FRS 2 -- cgit v1.2.3