Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
c2ee3a2d
Commit
c2ee3a2d
authored
Oct 10, 2002
by
Kai Germaschewski
Browse files
Options
Browse Files
Download
Plain Diff
Merge
http://linux.bkbits.net/linux-2.5
into tp1.ruhr-uni-bochum.de:/home/kai/src/kernel/v2.5/linux-2.5
parents
5b3e7241
8e5ee038
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
366 additions
and
335 deletions
+366
-335
drivers/isdn/i4l/isdn_common.c
drivers/isdn/i4l/isdn_common.c
+26
-51
drivers/isdn/i4l/isdn_common.h
drivers/isdn/i4l/isdn_common.h
+1
-2
drivers/isdn/i4l/isdn_concap.c
drivers/isdn/i4l/isdn_concap.c
+0
-4
drivers/isdn/i4l/isdn_net.c
drivers/isdn/i4l/isdn_net.c
+0
-157
drivers/isdn/i4l/isdn_net.h
drivers/isdn/i4l/isdn_net.h
+0
-4
drivers/isdn/i4l/isdn_net_lib.c
drivers/isdn/i4l/isdn_net_lib.c
+330
-109
drivers/isdn/i4l/isdn_tty.c
drivers/isdn/i4l/isdn_tty.c
+1
-1
drivers/isdn/i4l/isdn_ttyfax.c
drivers/isdn/i4l/isdn_ttyfax.c
+1
-1
include/linux/isdn.h
include/linux/isdn.h
+7
-6
No files found.
drivers/isdn/i4l/isdn_common.c
View file @
c2ee3a2d
...
...
@@ -503,11 +503,14 @@ isdn_status_callback(isdn_ctrl * c)
retval
=
2
;
}
break
;
case
1
:
case
1
:
/* incoming call accepted by net interface */
list_for_each
(
l
,
&
isdn_net_devs
)
{
isdn_net_dev
*
p
=
list_entry
(
l
,
isdn_net_dev
,
global_list
);
if
(
p
->
isdn_slot
==
i
)
{
strcpy
(
cmd
.
parm
.
setup
.
eazmsn
,
p
->
mlp
->
msn
);
isdn_slot_set_usage
(
i
,
(
isdn_slot_usage
(
i
)
&
ISDN_USAGE_EXCLUSIVE
)
|
ISDN_USAGE_NET
);
strcpy
(
isdn_slot_num
(
i
),
c
->
parm
.
setup
.
phone
);
isdn_slot_command
(
i
,
ISDN_CMD_ACCEPTD
,
&
cmd
);
retval
=
1
;
break
;
...
...
@@ -1535,26 +1538,20 @@ isdn_get_free_slot(int usage, int l2_proto, int l3_proto,
if
(
USG_NONE
(
slot
[
i
].
usage
)
&&
(
slot
[
i
].
di
!=
-
1
))
{
int
d
=
slot
[
i
].
di
;
if
((
slot
[
i
].
usage
&
ISDN_USAGE_EXCLUSIVE
)
&&
((
pre_dev
!=
d
)
||
(
pre_chan
!=
slot
[
i
].
ch
)))
continue
;
if
(
!
strcmp
(
isdn_map_eaz2msn
(
msn
,
d
),
"-"
))
continue
;
if
(
slot
[
i
].
usage
&
ISDN_USAGE_DISABLED
)
continue
;
/* usage not allowed */
if
(
dev
->
drv
[
d
]
->
flags
&
DRV_FLAG_RUNNING
)
{
if
(
!
dev
->
drv
[
d
]
->
flags
&
DRV_FLAG_RUNNING
)
continue
;
if
(((
dev
->
drv
[
d
]
->
interface
->
features
&
features
)
==
features
)
||
(((
dev
->
drv
[
d
]
->
interface
->
features
&
vfeatures
)
==
vfeatures
)
&&
(
dev
->
drv
[
d
]
->
interface
->
features
&
ISDN_FEATURE_L2_TRANS
)))
{
if
((
pre_dev
<
0
)
||
(
pre_chan
<
0
))
{
isdn_slot_set_usage
(
i
,
(
isdn_slot_usage
(
i
)
&
ISDN_USAGE_EXCLUSIVE
)
|
usage
);
if
(
pre_dev
<
0
||
pre_chan
<
0
||
(
pre_dev
==
d
&&
pre_chan
==
slot
[
i
].
ch
))
{
isdn_slot_set_usage
(
i
,
usage
);
restore_flags
(
flags
);
return
i
;
}
else
if
((
pre_dev
==
d
)
&&
(
pre_chan
==
slot
[
i
].
ch
))
{
isdn_slot_set_usage
(
i
,
(
isdn_slot_usage
(
i
)
&
ISDN_USAGE_EXCLUSIVE
)
|
usage
);
restore_flags
(
flags
);
return
i
;
}
}
}
}
...
...
@@ -1571,17 +1568,16 @@ isdn_free_channel(int di, int ch, int usage)
int
sl
;
sl
=
isdn_dc2minor
(
di
,
ch
);
isdn_slot_free
(
sl
,
usage
);
isdn_slot_free
(
sl
);
}
void
isdn_slot_free
(
int
sl
,
int
usage
)
isdn_slot_free
(
int
sl
)
{
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
if
(
!
usage
||
(
slot
[
sl
].
usage
&
ISDN_USAGE_MASK
)
==
usage
)
{
strcpy
(
isdn_slot_num
(
sl
),
"???"
);
slot
[
sl
].
ibytes
=
0
;
slot
[
sl
].
obytes
=
0
;
...
...
@@ -1591,30 +1587,8 @@ isdn_slot_free(int sl, int usage)
isdn_v110_close
(
slot
[
sl
].
iv110
.
v110
);
slot
[
sl
].
iv110
.
v110
=
NULL
;
// 20.10.99 JIM, try to reinitialize v110 !
isdn_slot_set_usage
(
sl
,
isdn_slot_usage
(
sl
)
&
(
ISDN_USAGE_NONE
|
ISDN_USAGE_EXCLUSIVE
)
);
isdn_slot_set_usage
(
sl
,
ISDN_USAGE_NONE
);
skb_queue_purge
(
&
dev
->
drv
[
isdn_slot_driver
(
sl
)]
->
rpqueue
[
isdn_slot_channel
(
sl
)]);
}
restore_flags
(
flags
);
}
/*
* Cancel Exclusive-Flag for ISDN-channel
*/
void
isdn_unexclusive_channel
(
int
di
,
int
ch
)
{
int
i
;
ulong
flags
;
save_flags
(
flags
);
cli
();
for
(
i
=
0
;
i
<
ISDN_MAX_CHANNELS
;
i
++
)
if
((
slot
[
i
].
di
==
di
)
&&
(
slot
[
i
].
ch
==
ch
))
{
isdn_slot_set_usage
(
i
,
isdn_slot_usage
(
i
)
&
~
ISDN_USAGE_EXCLUSIVE
);
restore_flags
(
flags
);
return
;
}
restore_flags
(
flags
);
}
...
...
@@ -1959,6 +1933,7 @@ isdn_slot_command(int sl, int cmd, isdn_ctrl *ctrl)
case
ISDN_CMD_DIAL
:
if
(
dev
->
global_flags
&
ISDN_GLOBAL_STOPPED
)
return
-
EBUSY
;
/* fall through */
default:
ctrl
->
arg
=
isdn_slot_channel
(
sl
);
...
...
drivers/isdn/i4l/isdn_common.h
View file @
c2ee3a2d
...
...
@@ -64,7 +64,6 @@ extern int isdn_dc2minor(int di, int ch);
extern
void
isdn_info_update
(
void
);
extern
char
*
isdn_map_eaz2msn
(
char
*
msn
,
int
di
);
extern
void
isdn_timer_ctrl
(
int
tf
,
int
onoff
);
extern
void
isdn_unexclusive_channel
(
int
di
,
int
ch
);
extern
int
isdn_getnum
(
char
**
);
extern
int
isdn_msncmp
(
const
char
*
,
const
char
*
);
extern
int
isdn_add_channels
(
driver
*
,
int
,
int
,
int
);
...
...
@@ -85,7 +84,7 @@ struct dial_info {
};
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_free
(
int
slot
);
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
);
...
...
drivers/isdn/i4l/isdn_concap.c
View file @
c2ee3a2d
...
...
@@ -21,8 +21,6 @@
#include "isdn_concap.h"
#include <linux/if_arp.h>
#ifdef CONFIG_ISDN_X25
/* The following set of device service operations are for encapsulation
protocols that require for reliable datalink semantics. That means:
...
...
@@ -255,5 +253,3 @@ struct isdn_netif_ops isdn_x25_ops = {
.
open
=
isdn_x25_open
,
.
close
=
isdn_x25_close
,
};
#endif
/* CONFIG_ISDN_X25 */
drivers/isdn/i4l/isdn_net.c
View file @
c2ee3a2d
...
...
@@ -423,163 +423,6 @@ isdn_net_rcv_skb(int idx, struct sk_buff *skb)
return
0
;
}
/*
* An incoming call-request has arrived.
* Search the interface-chain for an appropriate interface.
* If found, connect the interface to the ISDN-channel and initiate
* D- and B-Channel-setup. If secure-flag is set, accept only
* configured phone-numbers. If callback-flag is set, initiate
* callback-dialing.
*
* Return-Value: 0 = No appropriate interface for this call.
* 1 = Call accepted
* 2 = Reject call, wait cbdelay, then call back
* 3 = Reject call
* 4 = Wait cbdelay, then call back
* 5 = No appropriate interface for this call,
* would eventually match if CID was longer.
*/
int
isdn_net_find_icall
(
int
di
,
int
ch
,
int
idx
,
setup_parm
*
setup
)
{
char
*
eaz
;
unsigned
char
si1
,
si2
;
int
match_more
=
0
;
int
retval
;
struct
list_head
*
l
;
struct
isdn_net_phone
*
n
;
ulong
flags
;
char
nr
[
32
];
char
*
my_eaz
;
int
slot
=
isdn_dc2minor
(
di
,
ch
);
/* Search name in netdev-chain */
save_flags
(
flags
);
cli
();
if
(
!
setup
->
phone
[
0
])
{
nr
[
0
]
=
'0'
;
nr
[
1
]
=
'\0'
;
printk
(
KERN_INFO
"isdn_net: Incoming call without OAD, assuming '0'
\n
"
);
}
else
{
strcpy
(
nr
,
setup
->
phone
);
}
si1
=
setup
->
si1
;
si2
=
setup
->
si2
;
if
(
!
setup
->
eazmsn
[
0
])
{
printk
(
KERN_WARNING
"isdn_net: Incoming call without CPN, assuming '0'
\n
"
);
eaz
=
"0"
;
}
else
{
eaz
=
setup
->
eazmsn
;
}
if
(
dev
->
net_verbose
>
1
)
printk
(
KERN_INFO
"isdn_net: call from %s,%d,%d -> %s
\n
"
,
nr
,
si1
,
si2
,
eaz
);
/* Accept DATA and VOICE calls at this stage
local eaz is checked later for allowed call types */
if
((
si1
!=
7
)
&&
(
si1
!=
1
))
{
restore_flags
(
flags
);
if
(
dev
->
net_verbose
>
1
)
printk
(
KERN_INFO
"isdn_net: Service-Indicator not 1 or 7, ignored
\n
"
);
return
0
;
}
n
=
NULL
;
dbg_net_icall
(
"n_fi: di=%d ch=%d idx=%d usg=%d
\n
"
,
di
,
ch
,
idx
,
isdn_slot_usage
(
idx
));
list_for_each
(
l
,
&
isdn_net_devs
)
{
isdn_net_dev
*
idev
=
list_entry
(
l
,
isdn_net_dev
,
global_list
);
isdn_net_local
*
mlp
=
idev
->
mlp
;
/* check acceptable call types for DOV */
dbg_net_icall
(
"n_fi: if='%s', l.msn=%s, l.flags=%#x, l.dstate=%d
\n
"
,
idev
->
name
,
mlp
->
msn
,
mlp
->
flags
,
idev
->
fi
.
state
);
my_eaz
=
isdn_slot_map_eaz2msn
(
slot
,
mlp
->
msn
);
if
(
si1
==
1
)
{
/* it's a DOV call, check if we allow it */
if
(
*
my_eaz
==
'v'
||
*
my_eaz
==
'V'
||
*
my_eaz
==
'b'
||
*
my_eaz
==
'B'
)
my_eaz
++
;
/* skip to allow a match */
else
continue
;
/* force non match */
}
else
{
/* it's a DATA call, check if we allow it */
if
(
*
my_eaz
==
'b'
||
*
my_eaz
==
'B'
)
my_eaz
++
;
/* skip to allow a match */
}
switch
(
isdn_msncmp
(
eaz
,
my_eaz
))
{
case
1
:
continue
;
case
2
:
match_more
=
1
;
continue
;
}
if
(
isdn_net_bound
(
idev
))
continue
;
if
(
!
USG_NONE
(
isdn_slot_usage
(
idx
)))
continue
;
dbg_net_icall
(
"n_fi: match1, pdev=%d pch=%d
\n
"
,
idev
->
pre_device
,
idev
->
pre_channel
);
if
(
isdn_slot_usage
(
idx
)
&
ISDN_USAGE_EXCLUSIVE
&&
(
idev
->
pre_channel
!=
ch
||
idev
->
pre_device
!=
di
))
{
dbg_net_icall
(
"n_fi: excl check failed
\n
"
);
continue
;
}
dbg_net_icall
(
"n_fi: match2
\n
"
);
if
(
mlp
->
flags
&
ISDN_NET_SECURE
)
{
list_for_each_entry
(
n
,
&
mlp
->
phone
[
0
],
list
)
{
if
(
!
isdn_msncmp
(
nr
,
n
->
num
))
{
goto
found
;
}
}
continue
;
}
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
(
*
mlp
)
==
ISDN_NET_DM_OFF
)
{
restore_flags
(
flags
);
printk
(
KERN_INFO
"incoming call, interface %s `stopped' -> rejected
\n
"
,
idev
->
name
);
return
3
;
}
/*
* Is the interface up?
* If not, reject the call actively.
*/
if
(
!
isdn_net_device_started
(
idev
))
{
restore_flags
(
flags
);
printk
(
KERN_INFO
"%s: incoming call, interface down -> rejected
\n
"
,
idev
->
name
);
return
3
;
}
if
(
mlp
->
flags
&
ISDN_NET_CALLBACK
)
{
retval
=
isdn_net_do_callback
(
idev
);
restore_flags
(
flags
);
return
retval
;
}
printk
(
KERN_DEBUG
"%s: call from %s -> %s accepted
\n
"
,
idev
->
name
,
nr
,
eaz
);
isdn_net_accept
(
idev
,
idx
,
nr
);
restore_flags
(
flags
);
return
1
;
}
if
(
dev
->
net_verbose
)
printk
(
KERN_INFO
"isdn_net: call from %s -> %d %s ignored
\n
"
,
nr
,
slot
,
eaz
);
restore_flags
(
flags
);
return
(
match_more
==
2
)
?
5
:
0
;
}
/*
* This is called from certain upper protocol layers (multilink ppp
* and x25iface encapsulation module) that want to initiate dialing
...
...
drivers/isdn/i4l/isdn_net.h
View file @
c2ee3a2d
...
...
@@ -43,11 +43,7 @@ extern int register_isdn_netif(int encap, struct isdn_netif_ops *ops);
extern
int
isdn_net_autodial
(
struct
sk_buff
*
skb
,
struct
net_device
*
ndev
);
extern
int
isdn_net_start_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
ndev
);
extern
int
isdn_net_bind_channel
(
isdn_net_dev
*
idev
,
int
slot
);
extern
void
isdn_net_unbind_channel
(
isdn_net_dev
*
idev
);
extern
int
isdn_net_dial
(
isdn_net_dev
*
idev
);
extern
void
isdn_net_accept
(
isdn_net_dev
*
idev
,
int
slot
,
char
*
nr
);
extern
int
isdn_net_do_callback
(
isdn_net_dev
*
idev
);
extern
int
isdn_net_bsent
(
isdn_net_dev
*
idev
,
isdn_ctrl
*
c
);
...
...
drivers/isdn/i4l/isdn_net_lib.c
View file @
c2ee3a2d
...
...
@@ -10,6 +10,33 @@
* of the GNU General Public License, incorporated herein by reference.
*/
/* Locking works as follows:
*
* The configuration of isdn_net_devs works via ioctl on
* /dev/isdnctrl (for legacy reasons).
* All configuration accesses are globally serialized by means of
* the global semaphore &sem.
*
* All other uses of isdn_net_dev will only happen when the corresponding
* struct net_device has been opened. So in the non-config code we can
* rely on the config data not changing under us.
*
* To achieve this, in the "writing" ioctls, that is those which may change
* data, additionally grep the rtnl semaphore and check to make sure
* that the net_device has not been openend ("netif_running()")
*
* isdn_net_dev's are added to the global list "isdn_net_devs" in the
* configuration ioctls, so accesses to that list are protected by
* &sem as well.
*
* Incoming calls are signalled in IRQ context, so we cannot take &sem
* while walking the list of devices. To handle this, we put devices
* onto a "running" list, which is protected by a spin lock and can thus
* be traversed in IRQ context. If a matching isdn_net_dev is found,
* it's ref count shall be incremented, to make sure no racing
* net_device::close() can take it away under us.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/skbuff.h>
...
...
@@ -28,6 +55,31 @@
static
DECLARE_MUTEX
(
sem
);
LIST_HEAD
(
isdn_net_devs
);
/* Linked list of isdn_net_dev's */
// FIXME static
/* Reference counting for net devices (they work on isdn_net_local *,
* but count references to the related isdn_net_dev's as well.
* Basic rule: When state of isdn_net_dev changes from ST_NULL -> sth,
* get a reference, when it changes back to ST_NULL, put it
*/
static
inline
void
lp_get
(
isdn_net_local
*
lp
)
{
if
(
atomic_read
(
&
lp
->
refcnt
)
<
1
)
isdn_BUG
();
atomic_inc
(
&
lp
->
refcnt
);
}
static
inline
void
lp_put
(
isdn_net_local
*
lp
)
{
atomic_dec
(
&
lp
->
refcnt
);
/* the last reference, the list should always remain */
if
(
atomic_read
(
&
lp
->
refcnt
)
<
1
)
isdn_BUG
();
}
int
isdn_net_handle_event
(
isdn_net_dev
*
idev
,
int
pr
,
void
*
arg
);
/* FIXME */
static
void
isdn_net_tasklet
(
unsigned
long
data
);
...
...
@@ -39,6 +91,7 @@ static struct fsm isdn_net_fsm;
enum
{
ST_NULL
,
ST_OUT_BOUND
,
ST_OUT_WAIT_DCONN
,
ST_OUT_WAIT_BCONN
,
ST_IN_WAIT_DCONN
,
...
...
@@ -51,6 +104,7 @@ enum {
static
char
*
isdn_net_st_str
[]
=
{
"ST_NULL"
,
"ST_OUT_BOUND"
,
"ST_OUT_WAIT_DCONN"
,
"ST_OUT_WAIT_BCONN"
,
"ST_IN_WAIT_DCONN"
,
...
...
@@ -74,7 +128,9 @@ enum {
EV_STAT_BHUP
,
EV_STAT_CINF
,
EV_STAT_BSENT
,
EV_CMD_DIAL
,
EV_DO_DIAL
,
EV_DO_CALLBACK
,
EV_DO_ACCEPT
,
};
static
char
*
isdn_net_ev_str
[]
=
{
...
...
@@ -90,7 +146,9 @@ static char *isdn_net_ev_str[] = {
"EV_STAT_BHUP"
,
"EV_STAT_CINF"
,
"EV_STAT_BSENT"
,
"EV_CMD_DIAL"
,
"EV_DO_DIAL"
,
"EV_DO_CALLBACK"
,
"EV_DO_ACCEPT"
,
};
/* ====================================================================== */
...
...
@@ -225,21 +283,18 @@ isdn_net_bind(isdn_net_dev *idev, isdn_net_ioctl_cfg *cfg)
goto
out
;
}
if
(
idev
->
exclusive
>=
0
)
{
isdn_unexclusive_channel
(
idev
->
pre_device
,
idev
->
pre_channel
);
isdn_free_channel
(
idev
->
pre_device
,
idev
->
pre_channel
,
ISDN_USAGE_NET
);
isdn_slot_free
(
idev
->
exclusive
);
idev
->
exclusive
=
-
1
;
}
if
(
cfg
->
exclusive
)
{
/* If binding is exclusive, try to grab the channel */
idev
->
exclusive
=
isdn_get_free_slot
(
ISDN_USAGE_NET
,
mlp
->
l2_proto
,
mlp
->
l3_proto
,
drvidx
,
chidx
,
cfg
->
eaz
);
idev
->
exclusive
=
isdn_get_free_slot
(
ISDN_USAGE_NET
|
ISDN_USAGE_EXCLUSIVE
,
mlp
->
l
2_proto
,
mlp
->
l
3_proto
,
drvidx
,
chidx
,
cfg
->
eaz
);
if
(
idev
->
exclusive
<
0
)
{
/* Grab failed, because desired channel is in use */
retval
=
-
EBUSY
;
goto
out
;
}
/* All went ok, so update isdninfo */
isdn_slot_set_usage
(
idev
->
exclusive
,
ISDN_USAGE_EXCLUSIVE
);
}
idev
->
pre_device
=
drvidx
;
idev
->
pre_channel
=
chidx
;
...
...
@@ -360,6 +415,7 @@ isdn_net_addif(char *name, isdn_net_local *mlp)
}
}
list_add
(
&
idev
->
global_list
,
&
isdn_net_devs
);
return
0
;
}
...
...
@@ -417,7 +473,7 @@ isdn_net_dev_delete(isdn_net_dev *idev)
isdn_net_rmallphone
(
idev
);
if
(
idev
->
exclusive
>=
0
)
isdn_
unexclusive_channel
(
idev
->
pre_device
,
idev
->
pre_channel
);
isdn_
slot_free
(
idev
->
exclusive
);
list_del
(
&
idev
->
slaves
);
...
...
@@ -978,6 +1034,9 @@ isdn_net_exit(void)
/* interface to network layer */
/* ====================================================================== */
static
spinlock_t
running_devs_lock
=
SPIN_LOCK_UNLOCKED
;
static
LIST_HEAD
(
running_devs
);
/*
* Open/initialize the board.
*/
...
...
@@ -985,6 +1044,7 @@ static int
isdn_net_open
(
struct
net_device
*
dev
)
{
isdn_net_local
*
lp
=
dev
->
priv
;
unsigned
long
flags
;
int
retval
=
0
;
if
(
!
lp
->
ops
)
...
...
@@ -997,6 +1057,12 @@ isdn_net_open(struct net_device *dev)
return
retval
;
netif_start_queue
(
dev
);
atomic_set
(
&
lp
->
refcnt
,
1
);
spin_lock_irqsave
(
&
running_devs_lock
,
flags
);
list_add
(
&
lp
->
running_devs
,
&
running_devs
);
spin_unlock_irqrestore
(
&
running_devs_lock
,
flags
);
return
0
;
}
...
...
@@ -1008,8 +1074,9 @@ static int
isdn_net_close
(
struct
net_device
*
dev
)
{
isdn_net_local
*
lp
=
dev
->
priv
;
struct
list_head
*
l
,
*
n
;
isdn_net_dev
*
sdev
;
struct
list_head
*
l
,
*
n
;
unsigned
long
flags
;
if
(
lp
->
ops
->
close
)
lp
->
ops
->
close
(
lp
);
...
...
@@ -1020,6 +1087,20 @@ isdn_net_close(struct net_device *dev)
sdev
=
list_entry
(
l
,
isdn_net_dev
,
online
);
isdn_net_hangup
(
sdev
);
}
/* The hangup will make the refcnt drop back to
* 1 (referenced by list only) soon. */
spin_lock_irqsave
(
&
running_devs_lock
,
flags
);
while
(
atomic_read
(
&
dev
->
refcnt
)
!=
1
)
{
spin_unlock_irqrestore
(
&
running_devs_lock
,
flags
);
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
(
HZ
/
10
);
spin_lock_irqsave
(
&
running_devs_lock
,
flags
);
}
/* We have the only reference and list lock, so
* nobody can get another reference. */
list_del
(
&
lp
->
running_devs
);
spin_unlock_irqrestore
(
&
running_devs_lock
,
flags
);
return
0
;
}
...
...
@@ -1101,43 +1182,13 @@ isdn_net_dial_timer(unsigned long data)
isdn_net_handle_event
(
idev
,
idev
->
dial_event
,
NULL
);
}
/*
* Assign an ISDN-channel to a net-interface
*/
int
isdn_net_bind_channel
(
isdn_net_dev
*
idev
,
int
slot
)
{
isdn_net_local
*
mlp
=
idev
->
mlp
;
int
retval
=
0
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
idev
->
isdn_slot
=
slot
;
isdn_slot_set_idev
(
idev
->
isdn_slot
,
idev
);
if
(
mlp
->
ops
->
bind
)
retval
=
mlp
->
ops
->
bind
(
idev
);
if
(
retval
<
0
)
isdn_net_unbind_channel
(
idev
);
restore_flags
(
flags
);
return
retval
;
}
/*
* Unbind a net-interface
*/
void
static
void
isdn_net_unbind_channel
(
isdn_net_dev
*
idev
)
{
isdn_net_local
*
mlp
=
idev
->
mlp
;
ulong
flags
;
save_flags
(
flags
);
cli
();
if
(
idev
->
isdn_slot
<
0
)
{
isdn_BUG
();
...
...
@@ -1147,57 +1198,65 @@ isdn_net_unbind_channel(isdn_net_dev *idev)
if
(
mlp
->
ops
->
unbind
)
mlp
->
ops
->
unbind
(
idev
);
skb_queue_purge
(
&
idev
->
super_tx_queue
);
isdn_slot_set_idev
(
idev
->
isdn_slot
,
NULL
);
fsm_change_state
(
&
idev
->
fi
,
ST_NULL
);
skb_queue_purge
(
&
idev
->
super_tx_queue
);
i
sdn_slot_set_idev
(
idev
->
isdn_slot
,
NULL
);
isdn_slot_free
(
idev
->
isdn_slot
,
ISDN_USAGE_NET
);
i
f
(
idev
->
isdn_slot
!=
idev
->
exclusive
)
isdn_slot_free
(
idev
->
isdn_slot
);
idev
->
isdn_slot
=
-
1
;
restore_flags
(
flags
);
if
(
idev
->
fi
.
state
!=
ST_NULL
)
{
lp_put
(
mlp
);
fsm_change_state
(
&
idev
->
fi
,
ST_NULL
);
}
}
int
isdn_net_dial
(
isdn_net_dev
*
idev
)
/*
* Assign an ISDN-channel to a net-interface
*/
static
int
isdn_net_bind_channel
(
isdn_net_dev
*
idev
,
int
slot
)
{
int
slot
;
isdn_net_local
*
mlp
=
idev
->
mlp
;
int
retval
=
0
;
i
f
(
isdn_net_bound
(
idev
))
return
-
EBUSY
;
i
dev
->
isdn_slot
=
slot
;
isdn_slot_set_idev
(
idev
->
isdn_slot
,
idev
)
;
if
(
idev
->
exclusive
>=
0
)
slot
=
idev
->
exclusive
;
else
slot
=
isdn_get_free_slot
(
ISDN_USAGE_NET
,
mlp
->
l2_proto
,
mlp
->
l3_proto
,
idev
->
pre_device
,
idev
->
pre_channel
,
mlp
->
msn
);
if
(
slot
<
0
)
goto
err
;
if
(
mlp
->
ops
->
bind
)
retval
=
mlp
->
ops
->
bind
(
idev
);
if
(
retval
<
0
)
isdn_net_unbind_channel
(
idev
);
isdn_slot_set_usage
(
slot
,
isdn_slot_usage
(
slot
)
|
ISDN_USAGE_OUTGOING
);
return
retval
;
}
if
(
isdn_net_bind_channel
(
idev
,
slot
)
<
0
)
goto
err
;
int
isdn_net_dial
(
isdn_net_dev
*
idev
)
{
int
retval
;
/* Initiate dialing */
fsm_event
(
&
idev
->
fi
,
EV_CMD_DIAL
,
NULL
);
return
0
;
lp_get
(
idev
->
mlp
);
retval
=
fsm_event
(
&
idev
->
fi
,
EV_DO_DIAL
,
NULL
);
if
(
retval
==
-
ESRCH
)
/* event not handled in this state */
retval
=
-
EBUSY
;
err:
return
-
EAGAIN
;
if
(
retval
)
lp_put
(
idev
->
mlp
);
return
retval
;
}
void
isdn_net_accept
(
isdn_net_dev
*
idev
,
int
slot
,
char
*
nr
)
static
int
accept_icall
(
struct
fsm_inst
*
fi
,
int
pr
,
void
*
arg
)
{
isdn_net_dev
*
idev
=
fi
->
userdata
;
isdn_net_local
*
mlp
=
idev
->
mlp
;
isdn_ctrl
cmd
;
strcpy
(
isdn_slot_num
(
slot
),
nr
);
isdn_slot_set_usage
(
slot
,
(
isdn_slot_usage
(
slot
)
&
ISDN_USAGE_EXCLUSIVE
)
|
ISDN_USAGE_NET
);
int
slot
=
(
int
)
arg
;
isdn_net_bind_channel
(
idev
,
slot
);
...
...
@@ -1215,47 +1274,191 @@ isdn_net_accept(isdn_net_dev *idev, int slot, char *nr)
idev
->
dial_event
=
EV_TIMER_INCOMING
;
add_timer
(
&
idev
->
dial_timer
);
fsm_change_state
(
&
idev
->
fi
,
ST_IN_WAIT_DCONN
);
return
0
;
}
int
isdn_net_do_callback
(
isdn_net_dev
*
idev
)
static
int
do_callback
(
struct
fsm_inst
*
fi
,
int
pr
,
void
*
arg
)
{
isdn_net_dev
*
idev
=
fi
->
userdata
;
isdn_net_local
*
mlp
=
idev
->
mlp
;
int
slot
;
/*
* Is the state MANUAL?
* If so, no callback can be made,
* so reject actively.
*/
if
(
ISDN_NET_DIALMODE
(
*
mlp
)
==
ISDN_NET_DM_OFF
)
{
printk
(
KERN_INFO
"incoming call for callback, interface %s `off' -> rejected
\n
"
,
idev
->
name
);
return
3
;
}
printk
(
KERN_DEBUG
"%s: start callback
\n
"
,
idev
->
name
);
/* Grab a free ISDN-Channel */
slot
=
isdn_get_free_slot
(
ISDN_USAGE_NET
,
mlp
->
l2_proto
,
mlp
->
l3_proto
,
idev
->
pre_device
,
idev
->
pre_channel
,
mlp
->
msn
);
if
(
slot
<
0
)
goto
err
;
isdn_slot_set_usage
(
slot
,
isdn_slot_usage
(
slot
)
|
ISDN_USAGE_OUTGOING
);
if
(
isdn_net_bind_channel
(
idev
,
slot
)
<
0
)
goto
err
;
printk
(
KERN_DEBUG
"%s: start callback
\n
"
,
idev
->
name
);
/* Setup dialstate. */
idev
->
dial_timer
.
expires
=
jiffies
+
mlp
->
cbdelay
;
idev
->
dial_event
=
EV_TIMER_CB_IN
;
add_timer
(
&
idev
->
dial_timer
);
fsm_change_state
(
&
idev
->
fi
,
ST_WAIT_BEFORE_CB
);
return
0
;
}
static
int
isdn_net_dev_icall
(
isdn_net_dev
*
idev
,
int
di
,
int
ch
,
int
si1
,
char
*
eaz
,
char
*
nr
)
{
isdn_net_local
*
mlp
=
idev
->
mlp
;
struct
isdn_net_phone
*
ph
;
int
slot
=
isdn_dc2minor
(
di
,
ch
);
char
*
my_eaz
;
/* check acceptable call types for DOV */
dbg_net_icall
(
"n_fi: if='%s', l.msn=%s, l.flags=%#x, l.dstate=%d
\n
"
,
idev
->
name
,
mlp
->
msn
,
mlp
->
flags
,
idev
->
fi
.
state
);
my_eaz
=
isdn_slot_map_eaz2msn
(
slot
,
mlp
->
msn
);
if
(
si1
==
1
)
{
/* it's a DOV call, check if we allow it */
if
(
*
my_eaz
==
'v'
||
*
my_eaz
==
'V'
||
*
my_eaz
==
'b'
||
*
my_eaz
==
'B'
)
my_eaz
++
;
/* skip to allow a match */
else
return
0
;
/* no match */
}
else
{
/* it's a DATA call, check if we allow it */
if
(
*
my_eaz
==
'b'
||
*
my_eaz
==
'B'
)
my_eaz
++
;
/* skip to allow a match */
}
if
(
!
USG_NONE
(
isdn_slot_usage
(
slot
)))
// FIXME?
return
0
;
/* check called number */
switch
(
isdn_msncmp
(
eaz
,
my_eaz
))
{
case
1
:
/* no match */
return
0
;
case
2
:
/* matches so far */
return
5
;
}
dbg_net_icall
(
"%s: pdev=%d di=%d pch=%d ch = %d
\n
"
,
idev
->
name
,
idev
->
pre_device
,
di
,
idev
->
pre_channel
,
ch
);
/* check if exclusive */
if
((
isdn_slot_usage
(
slot
)
&
ISDN_USAGE_EXCLUSIVE
)
&&
(
idev
->
pre_channel
!=
ch
||
idev
->
pre_device
!=
di
))
{
dbg_net_icall
(
"%s: excl check failed
\n
"
,
idev
->
name
);
return
0
;
}
/* check calling number */
dbg_net_icall
(
"%s: secure
\n
"
,
idev
->
name
);
if
(
mlp
->
flags
&
ISDN_NET_SECURE
)
{
list_for_each_entry
(
ph
,
&
mlp
->
phone
[
0
],
list
)
{
if
(
isdn_msncmp
(
nr
,
ph
->
num
)
==
0
)
goto
found
;
}
return
0
;
}
found:
/* check dial mode */
if
(
ISDN_NET_DIALMODE
(
*
mlp
)
==
ISDN_NET_DM_OFF
)
{
printk
(
KERN_INFO
"%s: incoming call, stopped -> rejected
\n
"
,
idev
->
name
);
return
3
;
}
lp_get
(
mlp
);
/* check callback */
if
(
mlp
->
flags
&
ISDN_NET_CALLBACK
)
{
if
(
fsm_event
(
&
idev
->
fi
,
EV_DO_CALLBACK
,
NULL
))
{
lp_put
(
mlp
);
return
0
;
}
/* Initiate dialing by returning 2 or 4 */
return
(
mlp
->
flags
&
ISDN_NET_CBHUP
)
?
2
:
4
;
}
printk
(
KERN_INFO
"%s: call from %s -> %s accepted
\n
"
,
idev
->
name
,
nr
,
eaz
);
err:
if
(
fsm_event
(
&
idev
->
fi
,
EV_DO_ACCEPT
,
(
void
*
)
slot
))
{
lp_put
(
mlp
);
return
0
;
}
return
1
;
// accepted
}
/*
* An incoming call-request has arrived.
* Search the interface-chain for an appropriate interface.
* If found, connect the interface to the ISDN-channel and initiate
* D- and B-Channel-setup. If secure-flag is set, accept only
* configured phone-numbers. If callback-flag is set, initiate
* callback-dialing.
*
* Return-Value: 0 = No appropriate interface for this call.
* 1 = Call accepted
* 2 = Reject call, wait cbdelay, then call back
* 3 = Reject call
* 4 = Wait cbdelay, then call back
* 5 = No appropriate interface for this call,
* would eventually match if CID was longer.
*/
int
isdn_net_find_icall
(
int
di
,
int
ch
,
int
idx
,
setup_parm
*
setup
)
{
isdn_net_local
*
lp
;
isdn_net_dev
*
idev
;
char
*
nr
,
*
eaz
;
unsigned
char
si1
,
si2
;
int
retval
;
unsigned
long
flags
;
/* fix up calling number */
if
(
!
setup
->
phone
[
0
])
{
printk
(
KERN_INFO
"isdn_net: Incoming call without OAD, assuming '0'
\n
"
);
nr
=
"0"
;
}
else
{
nr
=
setup
->
phone
;
}
/* fix up called number */
if
(
!
setup
->
eazmsn
[
0
])
{
printk
(
KERN_INFO
"isdn_net: Incoming call without CPN, assuming '0'
\n
"
);
eaz
=
"0"
;
}
else
{
eaz
=
setup
->
eazmsn
;
}
si1
=
setup
->
si1
;
si2
=
setup
->
si2
;
if
(
dev
->
net_verbose
>
1
)
printk
(
KERN_INFO
"isdn_net: call from %s,%d,%d -> %s
\n
"
,
nr
,
si1
,
si2
,
eaz
);
/* check service indicator */
/* Accept DATA and VOICE calls at this stage
local eaz is checked later for allowed call types */
if
((
si1
!=
7
)
&&
(
si1
!=
1
))
{
if
(
dev
->
net_verbose
>
1
)
printk
(
KERN_INFO
"isdn_net: "
"Service-Indicator not 1 or 7, ignored
\n
"
);
return
0
;
}
dbg_net_icall
(
"n_fi: di=%d ch=%d idx=%d usg=%d
\n
"
,
di
,
ch
,
idx
,
isdn_slot_usage
(
idx
));
retval
=
0
;
spin_lock_irqsave
(
&
running_devs_lock
,
flags
);
list_for_each_entry
(
lp
,
&
running_devs
,
running_devs
)
{
lp_get
(
lp
);
spin_unlock_irqrestore
(
&
running_devs_lock
,
flags
);
list_for_each_entry
(
idev
,
&
lp
->
slaves
,
slaves
)
{
retval
=
isdn_net_dev_icall
(
idev
,
di
,
ch
,
si1
,
eaz
,
nr
);
if
(
retval
>
0
)
break
;
}
spin_lock_irqsave
(
&
running_devs_lock
,
flags
);
lp_put
(
lp
);
if
(
retval
>
0
)
break
;
}
spin_unlock_irqrestore
(
&
running_devs_lock
,
flags
);
if
(
!
retval
)
{
if
(
dev
->
net_verbose
)
printk
(
KERN_INFO
"isdn_net: call "
"from %s -> %s ignored
\n
"
,
nr
,
eaz
);
}
return
retval
;
}
/* ---------------------------------------------------------------------- */
...
...
@@ -1283,23 +1486,39 @@ static int dialout_next(struct fsm_inst *fi, int pr, void *arg);
/* Initiate dialout. */
static
int
d
ialout_first
(
struct
fsm_inst
*
fi
,
int
pr
,
void
*
arg
)
d
o_dial
(
struct
fsm_inst
*
fi
,
int
pr
,
void
*
arg
)
{
isdn_net_dev
*
idev
=
fi
->
userdata
;
isdn_net_local
*
mlp
=
idev
->
mlp
;
int
slot
;
if
(
ISDN_NET_DIALMODE
(
*
mlp
)
==
ISDN_NET_DM_OFF
)
{
isdn_net_unbind_channel
(
idev
);
if
(
ISDN_NET_DIALMODE
(
*
mlp
)
==
ISDN_NET_DM_OFF
)
return
-
EPERM
;
}
if
(
list_empty
(
&
mlp
->
phone
[
1
]))
{
isdn_net_unbind_channel
(
idev
);
if
(
list_empty
(
&
mlp
->
phone
[
1
]))
/* no number to dial ? */
return
-
EINVAL
;
if
(
idev
->
exclusive
>=
0
)
slot
=
idev
->
exclusive
;
else
slot
=
isdn_get_free_slot
(
ISDN_USAGE_NET
,
mlp
->
l2_proto
,
mlp
->
l3_proto
,
idev
->
pre_device
,
idev
->
pre_channel
,
mlp
->
msn
);
if
(
slot
<
0
)
return
-
EAGAIN
;
if
(
isdn_net_bind_channel
(
idev
,
slot
)
<
0
)
{
/* has freed the slot as well */
return
-
EAGAIN
;
}
fsm_change_state
(
fi
,
ST_OUT_BOUND
);
idev
->
dial
=
0
;
idev
->
dialretry
=
0
;
return
dialout_next
(
fi
,
pr
,
arg
);
dialout_next
(
fi
,
pr
,
arg
);
return
0
;
}
/* Try dialing the next number. */
...
...
@@ -1598,7 +1817,9 @@ got_bsent(struct fsm_inst *fi, int pr, void *arg)
}
static
struct
fsm_node
isdn_net_fn_tbl
[]
=
{
{
ST_NULL
,
EV_CMD_DIAL
,
dialout_first
},
{
ST_NULL
,
EV_DO_DIAL
,
do_dial
},
{
ST_NULL
,
EV_DO_ACCEPT
,
accept_icall
},
{
ST_NULL
,
EV_DO_CALLBACK
,
do_callback
},
{
ST_OUT_WAIT_DCONN
,
EV_TIMER_DIAL
,
dial_timeout
},
{
ST_OUT_WAIT_DCONN
,
EV_STAT_DCONN
,
out_dconn
},
...
...
@@ -1624,7 +1845,7 @@ static struct fsm_node isdn_net_fn_tbl[] = {
{
ST_WAIT_DHUP
,
EV_STAT_DHUP
,
dhup
},
{
ST_WAIT_BEFORE_CB
,
EV_TIMER_CB_IN
,
d
ialout_first
},
{
ST_WAIT_BEFORE_CB
,
EV_TIMER_CB_IN
,
d
o_dial
},
{
ST_OUT_DIAL_WAIT
,
EV_TIMER_DIAL_WAIT
,
dialout_next
},
};
...
...
drivers/isdn/i4l/isdn_tty.c
View file @
c2ee3a2d
...
...
@@ -745,7 +745,7 @@ isdn_tty_modem_hup(modem_info * info, int local)
isdn_slot_all_eaz
(
slot
);
info
->
emu
.
mdmreg
[
REG_RINGCNT
]
=
0
;
isdn_slot_free
(
slot
,
0
);
isdn_slot_free
(
slot
);
isdn_slot_set_m_idx
(
slot
,
-
1
);
info
->
isdn_slot
=
-
1
;
}
...
...
drivers/isdn/i4l/isdn_ttyfax.c
View file @
c2ee3a2d
...
...
@@ -382,7 +382,7 @@ isdn_tty_cmd_FCLASS1(char **p, modem_info * info)
info
->
isdn_slot
=
i
;
isdn_slot_set_m_idx
(
i
,
info
->
line
);
isdn_slot_command
(
info
->
isdn_slot
,
ISDN_CMD_FAXCMD
,
&
c
);
isdn_slot_free
(
info
->
isdn_slot
,
ISDN_USAGE_FAX
);
isdn_slot_free
(
info
->
isdn_slot
);
isdn_slot_set_m_idx
(
i
,
-
1
);
info
->
isdn_slot
=
-
1
;
restore_flags
(
flags
);
...
...
include/linux/isdn.h
View file @
c2ee3a2d
...
...
@@ -339,10 +339,11 @@ typedef struct isdn_net_local_s {
/* phone[1] = Outgoing Numbers */
struct
list_head
slaves
;
/* list of all bundled channels */
struct
list_head
online
;
/* circular list of all bundled
channels, which are currently
online */
spinlock_t
online_lock
;
/* lock to protect queue */
struct
list_head
online
;
/* list of all bundled channels,
which are currently online */
spinlock_t
online_lock
;
/* lock to protect online list */
struct
list_head
running_devs
;
/* member of global running_devs */
atomic_t
refcnt
;
/* references held by ISDN code */
#ifdef CONFIG_ISDN_X25
struct
concap_device_ops
*
dops
;
/* callbacks used by encapsulator */
...
...
@@ -403,8 +404,8 @@ typedef struct isdn_net_dev_s {
isdn_net_local
*
mlp
;
/* Ptr to master device for all devs*/
struct
list_head
slaves
;
/*
Members of local->slaves
*/
struct
list_head
online
;
/*
Members of local->online
*/
struct
list_head
slaves
;
/*
member of local->slaves
*/
struct
list_head
online
;
/*
member of local->online
*/
char
name
[
10
];
/* Name of device */
struct
list_head
global_list
;
/* global list of all isdn_net_devs */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment