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
nexedi
linux
Commits
3b1022c5
Commit
3b1022c5
authored
Oct 11, 2002
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
http://linux-isdn.bkbits.net/linux-2.5.isdn
into home.transmeta.com:/home/torvalds/v2.5/linux
parents
798c67c3
c2ee3a2d
Changes
9
Hide 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 @
3b1022c5
...
...
@@ -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
]
->
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
);
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
;
}
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
||
(
pre_dev
==
d
&&
pre_chan
==
slot
[
i
].
ch
))
{
isdn_slot_set_usage
(
i
,
usage
);
restore_flags
(
flags
);
return
i
;
}
}
}
...
...
@@ -1571,50 +1568,27 @@ 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
;
strcpy
(
isdn_slot_num
(
sl
),
"???"
);
slot
[
sl
].
ibytes
=
0
;
slot
[
sl
].
obytes
=
0
;
// 20.10.99 JIM, try to reinitialize v110 !
slot
[
sl
].
iv110
.
v110emu
=
0
;
atomic_set
(
&
slot
[
sl
].
iv110
.
v110use
,
0
);
isdn_v110_close
(
slot
[
sl
].
iv110
.
v110
);
slot
[
sl
].
iv110
.
v110
=
NULL
;
slot
[
sl
].
iv110
.
v110emu
=
0
;
atomic_set
(
&
slot
[
sl
].
iv110
.
v110use
,
0
);
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
));
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
;
}
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
);
}
...
...
@@ -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 @
3b1022c5
...
...
@@ -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 @
3b1022c5
...
...
@@ -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 @
3b1022c5
...
...
@@ -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 @
3b1022c5
...
...
@@ -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 @
3b1022c5
...
...
@@ -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,58 +1198,66 @@ 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
);
isdn_slot_set_usage
(
slot
,
isdn_slot_usage
(
slot
)
|
ISDN_USAGE_OUTGOING
);
if
(
retval
<
0
)
isdn_net_unbind_channel
(
idev
);
if
(
isdn_net_bind_channel
(
idev
,
slot
)
<
0
)
goto
err
;
return
retval
;
}
/* Initiate dialing */
fsm_event
(
&
idev
->
fi
,
EV_CMD_DIAL
,
NULL
);
return
0
;
int
isdn_net_dial
(
isdn_net_dev
*
idev
)
{
int
retval
;
lp_get
(
idev
->
mlp
);
retval
=
fsm_event
(
&
idev
->
fi
,
EV_DO_DIAL
,
NULL
);
if
(
retval
==
-
ESRCH
)
/* event not handled in this state */
retval
=
-
EBUSY
;
if
(
retval
)
lp_put
(
idev
->
mlp
);
err:
return
-
EAGAIN
;
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
;
int
slot
=
(
int
)
arg
;
strcpy
(
isdn_slot_num
(
slot
),
nr
);
isdn_slot_set_usage
(
slot
,
(
isdn_slot_usage
(
slot
)
&
ISDN_USAGE_EXCLUSIVE
)
|
ISDN_USAGE_NET
);
isdn_net_bind_channel
(
idev
,
slot
);
idev
->
outgoing
=
0
;
...
...
@@ -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.
*/
printk
(
KERN_DEBUG
"%s: start callback
\n
"
,
idev
->
name
);
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
"
incoming call for callback, interface %s `off'
-> rejected
\n
"
,
printk
(
KERN_INFO
"
%s: incoming call, stopped
-> 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
;
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
);
isdn_slot_set_usage
(
slot
,
isdn_slot_usage
(
slot
)
|
ISDN_USAGE_OUTGOING
);
if
(
fsm_event
(
&
idev
->
fi
,
EV_DO_ACCEPT
,
(
void
*
)
slot
))
{
lp_put
(
mlp
);
return
0
;
}
return
1
;
// accepted
}
if
(
isdn_net_bind_channel
(
idev
,
slot
)
<
0
)
goto
err
;
/*
* 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
;
/* 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
);
/* 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
));
/* Initiate dialing by returning 2 or 4 */
return
(
mlp
->
flags
&
ISDN_NET_CBHUP
)
?
2
:
4
;
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
;
}
err:
return
0
;
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 @
3b1022c5
...
...
@@ -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 @
3b1022c5
...
...
@@ -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 @
3b1022c5
...
...
@@ -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