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
994b6e06
Commit
994b6e06
authored
Oct 06, 2002
by
Kai Germaschewski
Browse files
Options
Browse Files
Download
Plain Diff
ISDN: Merge Ingo's work_struct and my tasklet changes
parents
ab1180be
f31b5ddd
Changes
16
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
2583 additions
and
2678 deletions
+2583
-2678
Makefile
Makefile
+1
-1
drivers/isdn/i4l/Makefile
drivers/isdn/i4l/Makefile
+5
-3
drivers/isdn/i4l/isdn_ciscohdlck.c
drivers/isdn/i4l/isdn_ciscohdlck.c
+91
-80
drivers/isdn/i4l/isdn_common.c
drivers/isdn/i4l/isdn_common.c
+15
-184
drivers/isdn/i4l/isdn_common.h
drivers/isdn/i4l/isdn_common.h
+9
-11
drivers/isdn/i4l/isdn_concap.c
drivers/isdn/i4l/isdn_concap.c
+10
-11
drivers/isdn/i4l/isdn_concap.h
drivers/isdn/i4l/isdn_concap.h
+0
-14
drivers/isdn/i4l/isdn_fsm.c
drivers/isdn/i4l/isdn_fsm.c
+169
-0
drivers/isdn/i4l/isdn_fsm.h
drivers/isdn/i4l/isdn_fsm.h
+60
-0
drivers/isdn/i4l/isdn_net.c
drivers/isdn/i4l/isdn_net.c
+357
-2006
drivers/isdn/i4l/isdn_net.h
drivers/isdn/i4l/isdn_net.h
+66
-80
drivers/isdn/i4l/isdn_net_lib.c
drivers/isdn/i4l/isdn_net_lib.c
+1640
-0
drivers/isdn/i4l/isdn_ppp.c
drivers/isdn/i4l/isdn_ppp.c
+111
-220
drivers/isdn/i4l/isdn_ppp.h
drivers/isdn/i4l/isdn_ppp.h
+0
-14
include/linux/isdn.h
include/linux/isdn.h
+47
-43
include/linux/isdn_ppp.h
include/linux/isdn_ppp.h
+2
-11
No files found.
Makefile
View file @
994b6e06
...
...
@@ -81,7 +81,7 @@ ifneq ($(filter all,$(MAKECMDGOALS)),)
KBUILD_MODULES
:=
1
endif
export
KBUILD_MODULES
KBUILD_BUILTIN
export
KBUILD_MODULES
KBUILD_BUILTIN
KBUILD_VERBOSE
# Beautify output
# ---------------------------------------------------------------------------
...
...
drivers/isdn/i4l/Makefile
View file @
994b6e06
...
...
@@ -11,9 +11,11 @@ obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
# Multipart objects.
isdn-objs
:=
isdn_net.o isdn_tty.o
\
isdn_v110.o isdn_common.o
\
isdn_ciscohdlck.o
isdn-objs
:=
isdn_net.o isdn_net_lib.o
\
isdn_fsm.o
\
isdn_ciscohdlck.o
\
isdn_tty.o isdn_v110.o
\
isdn_common.o
\
# Optional parts of multipart objects.
...
...
drivers/isdn/i4l/isdn_ciscohdlck.c
View file @
994b6e06
...
...
@@ -24,9 +24,8 @@
* CISCO HDLC keepalive specific stuff
*/
static
struct
sk_buff
*
isdn_net_ciscohdlck_alloc_skb
(
isdn_net_
local
*
lp
,
int
len
)
isdn_net_ciscohdlck_alloc_skb
(
isdn_net_
dev
*
idev
,
int
len
)
{
isdn_net_dev
*
idev
=
lp
->
netdev
;
unsigned
short
hl
=
isdn_slot_hdrlen
(
idev
->
isdn_slot
);
struct
sk_buff
*
skb
;
...
...
@@ -43,63 +42,60 @@ isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len)
static
int
isdn_ciscohdlck_dev_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
ifr
,
int
cmd
)
{
isdn_net_local
*
lp
=
(
isdn_net_local
*
)
dev
->
priv
;
isdn_net_dev
*
idev
=
lp
->
netdev
;
isdn_net_local
*
mlp
=
dev
->
priv
;
unsigned
long
len
=
0
;
unsigned
long
expires
=
0
;
int
tmp
=
0
;
int
period
=
lp
->
cisco_keepalive_period
;
char
debserint
=
lp
->
cisco_debserint
;
int
period
;
char
debserint
;
int
rc
=
0
;
if
(
lp
->
p_encap
!=
ISDN_NET_ENCAP_CISCOHDLCK
)
if
(
m
lp
->
p_encap
!=
ISDN_NET_ENCAP_CISCOHDLCK
)
return
-
EINVAL
;
switch
(
cmd
)
{
/* get/set keepalive period */
case
SIOCGKEEPPERIOD
:
len
=
(
unsigned
long
)
sizeof
(
lp
->
cisco_keepalive_period
);
len
=
sizeof
(
m
lp
->
cisco_keepalive_period
);
if
(
copy_to_user
((
char
*
)
ifr
->
ifr_ifru
.
ifru_data
,
(
int
*
)
&
lp
->
cisco_keepalive_period
,
len
))
(
char
*
)
&
m
lp
->
cisco_keepalive_period
,
len
))
rc
=
-
EFAULT
;
break
;
case
SIOCSKEEPPERIOD
:
tmp
=
lp
->
cisco_keepalive_period
;
len
=
(
unsigned
long
)
sizeof
(
lp
->
cisco_keepalive_period
);
if
(
copy_from_user
((
int
*
)
&
period
,
(
char
*
)
ifr
->
ifr_ifru
.
ifru_data
,
len
))
len
=
sizeof
(
mlp
->
cisco_keepalive_period
);
if
(
copy_from_user
((
char
*
)
&
period
,
(
char
*
)
ifr
->
ifr_ifru
.
ifru_data
,
len
))
{
rc
=
-
EFAULT
;
if
((
period
>
0
)
&&
(
period
<=
32767
))
lp
->
cisco_keepalive_period
=
period
;
else
break
;
}
if
(
period
<=
0
||
period
>
32767
)
{
rc
=
-
EINVAL
;
if
(
!
rc
&&
(
tmp
!=
lp
->
cisco_keepalive_period
))
{
expires
=
(
unsigned
long
)(
jiffies
+
lp
->
cisco_keepalive_period
*
HZ
);
mod_timer
(
&
lp
->
cisco_timer
,
expires
);
printk
(
KERN_INFO
"%s: Keepalive period set "
"to %d seconds.
\n
"
,
idev
->
name
,
lp
->
cisco_keepalive_period
);
break
;
}
mod_timer
(
&
mlp
->
cisco_timer
,
jiffies
+
period
*
HZ
);
printk
(
KERN_INFO
"%s: Keepalive period set "
"to %d seconds.
\n
"
,
dev
->
name
,
period
);
mlp
->
cisco_keepalive_period
=
period
;
break
;
/* get/set debugging */
case
SIOCGDEBSERINT
:
len
=
(
unsigned
long
)
sizeof
(
lp
->
cisco_debserint
);
len
=
sizeof
(
m
lp
->
cisco_debserint
);
if
(
copy_to_user
((
char
*
)
ifr
->
ifr_ifru
.
ifru_data
,
(
char
*
)
&
lp
->
cisco_debserint
,
len
))
(
char
*
)
&
m
lp
->
cisco_debserint
,
len
))
rc
=
-
EFAULT
;
break
;
case
SIOCSDEBSERINT
:
len
=
(
unsigned
long
)
sizeof
(
lp
->
cisco_debserint
);
len
=
sizeof
(
m
lp
->
cisco_debserint
);
if
(
copy_from_user
((
char
*
)
&
debserint
,
(
char
*
)
ifr
->
ifr_ifru
.
ifru_data
,
len
))
(
char
*
)
ifr
->
ifr_ifru
.
ifru_data
,
len
))
{
rc
=
-
EFAULT
;
if
((
debserint
>=
0
)
&&
(
debserint
<=
64
))
lp
->
cisco_debserint
=
debserint
;
else
break
;
}
if
(
debserint
<
0
||
debserint
>
64
)
{
rc
=
-
EINVAL
;
break
;
}
mlp
->
cisco_debserint
=
debserint
;
break
;
default:
rc
=
-
EINVAL
;
...
...
@@ -112,42 +108,47 @@ isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
static
void
isdn_net_ciscohdlck_slarp_send_keepalive
(
unsigned
long
data
)
{
isdn_net_local
*
lp
=
(
isdn_net_local
*
)
data
;
isdn_net_dev
*
idev
=
lp
->
netdev
;
isdn_net_local
*
m
lp
=
(
isdn_net_local
*
)
data
;
isdn_net_dev
*
idev
;
struct
sk_buff
*
skb
;
unsigned
char
*
p
;
unsigned
long
last_cisco_myseq
=
lp
->
cisco_myseq
;
unsigned
long
last_cisco_myseq
=
m
lp
->
cisco_myseq
;
int
myseq_diff
=
0
;
lp
->
cisco_myseq
++
;
if
(
list_empty
(
&
mlp
->
online
))
{
isdn_BUG
();
return
;
}
idev
=
list_entry
(
mlp
->
online
.
next
,
isdn_net_dev
,
online
);
mlp
->
cisco_myseq
++
;
myseq_diff
=
(
lp
->
cisco_myseq
-
lp
->
cisco_mineseen
);
if
(
(
lp
->
cisco_line_state
)
&&
((
myseq_diff
>=
3
)
||
(
myseq_diff
<=
-
3
)
))
{
myseq_diff
=
(
mlp
->
cisco_myseq
-
m
lp
->
cisco_mineseen
);
if
(
mlp
->
cisco_line_state
&&
(
myseq_diff
>=
3
||
myseq_diff
<=
-
3
))
{
/* line up -> down */
lp
->
cisco_line_state
=
0
;
m
lp
->
cisco_line_state
=
0
;
printk
(
KERN_WARNING
"UPDOWN: Line protocol on Interface %s,"
" changed state to down
\n
"
,
idev
->
name
);
/* should stop routing higher-level data accross */
}
else
if
(
(
!
lp
->
cisco_line_state
)
&&
(
myseq_diff
>=
0
)
&&
(
myseq_diff
<=
2
)
)
{
}
else
if
(
!
mlp
->
cisco_line_state
&&
myseq_diff
>=
0
&&
myseq_diff
<=
2
)
{
/* line down -> up */
lp
->
cisco_line_state
=
1
;
m
lp
->
cisco_line_state
=
1
;
printk
(
KERN_WARNING
"UPDOWN: Line protocol on Interface %s,"
" changed state to up
\n
"
,
idev
->
name
);
/* restart routing higher-level data accross */
}
if
(
lp
->
cisco_debserint
)
if
(
m
lp
->
cisco_debserint
)
printk
(
KERN_DEBUG
"%s: HDLC "
"myseq %lu, mineseen %lu%c, yourseen %lu, %s
\n
"
,
idev
->
name
,
last_cisco_myseq
,
lp
->
cisco_mineseen
,
(
last_cisco_myseq
==
lp
->
cisco_mineseen
)
?
'*'
:
040
,
lp
->
cisco_yourseq
,
(
lp
->
cisco_line_state
)
?
"line up"
:
"line down"
);
idev
->
name
,
last_cisco_myseq
,
m
lp
->
cisco_mineseen
,
(
last_cisco_myseq
==
m
lp
->
cisco_mineseen
)
?
'*'
:
040
,
m
lp
->
cisco_yourseq
,
(
m
lp
->
cisco_line_state
)
?
"line up"
:
"line down"
);
skb
=
isdn_net_ciscohdlck_alloc_skb
(
lp
,
4
+
14
);
skb
=
isdn_net_ciscohdlck_alloc_skb
(
idev
,
4
+
14
);
if
(
!
skb
)
return
;
...
...
@@ -160,24 +161,29 @@ isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
/* slarp keepalive */
p
+=
put_u32
(
p
,
CISCO_SLARP_KEEPALIVE
);
p
+=
put_u32
(
p
,
lp
->
cisco_myseq
);
p
+=
put_u32
(
p
,
lp
->
cisco_yourseq
);
p
+=
put_u32
(
p
,
m
lp
->
cisco_myseq
);
p
+=
put_u32
(
p
,
m
lp
->
cisco_yourseq
);
p
+=
put_u16
(
p
,
0xffff
);
// reliablity, always 0xffff
isdn_net_write_super
(
lp
,
skb
);
lp
->
cisco_timer
.
expires
=
jiffies
+
lp
->
cisco_keepalive_period
*
HZ
;
isdn_net_write_super
(
idev
,
skb
);
add_timer
(
&
lp
->
cisco_timer
);
mod_timer
(
&
mlp
->
cisco_timer
,
jiffies
+
mlp
->
cisco_keepalive_period
*
HZ
);
}
static
void
isdn_net_ciscohdlck_slarp_send_request
(
isdn_net_local
*
lp
)
isdn_net_ciscohdlck_slarp_send_request
(
isdn_net_local
*
m
lp
)
{
isdn_net_dev
*
idev
;
struct
sk_buff
*
skb
;
unsigned
char
*
p
;
skb
=
isdn_net_ciscohdlck_alloc_skb
(
lp
,
4
+
14
);
if
(
list_empty
(
&
mlp
->
online
))
{
isdn_BUG
();
return
;
}
idev
=
list_entry
(
mlp
->
online
.
next
,
isdn_net_dev
,
online
);
skb
=
isdn_net_ciscohdlck_alloc_skb
(
idev
,
4
+
14
);
if
(
!
skb
)
return
;
...
...
@@ -194,12 +200,14 @@ isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp)
p
+=
put_u32
(
p
,
0
);
// netmask
p
+=
put_u16
(
p
,
0
);
// unused
isdn_net_write_super
(
lp
,
skb
);
isdn_net_write_super
(
idev
,
skb
);
}
static
void
isdn_ciscohdlck_connected
(
isdn_net_
local
*
lp
)
isdn_ciscohdlck_connected
(
isdn_net_
dev
*
idev
)
{
isdn_net_local
*
lp
=
idev
->
mlp
;
lp
->
cisco_myseq
=
0
;
lp
->
cisco_mineseen
=
0
;
lp
->
cisco_yourseq
=
0
;
...
...
@@ -218,27 +226,30 @@ isdn_ciscohdlck_connected(isdn_net_local *lp)
lp
->
cisco_timer
.
expires
=
jiffies
+
lp
->
cisco_keepalive_period
*
HZ
;
add_timer
(
&
lp
->
cisco_timer
);
}
isdn_net_device_wake_queue
(
lp
);
netif_wake_queue
(
&
lp
->
dev
);
}
static
void
isdn_ciscohdlck_disconnected
(
isdn_net_
local
*
lp
)
isdn_ciscohdlck_disconnected
(
isdn_net_
dev
*
idev
)
{
isdn_net_local
*
lp
=
idev
->
mlp
;
if
(
lp
->
p_encap
==
ISDN_NET_ENCAP_CISCOHDLCK
)
{
del_timer
(
&
lp
->
cisco_timer
);
}
}
static
void
isdn_net_ciscohdlck_slarp_send_reply
(
isdn_net_
local
*
lp
)
isdn_net_ciscohdlck_slarp_send_reply
(
isdn_net_
dev
*
idev
)
{
isdn_net_local
*
mlp
=
idev
->
mlp
;
struct
sk_buff
*
skb
;
unsigned
char
*
p
;
struct
in_device
*
in_dev
=
NULL
;
u32
addr
=
0
;
/* local ipv4 address */
u32
mask
=
0
;
/* local netmask */
if
((
in_dev
=
lp
->
netdev
->
dev
.
ip_ptr
)
!=
NULL
)
{
if
((
in_dev
=
mlp
->
dev
.
ip_ptr
)
!=
NULL
)
{
/* take primary(first) address of interface */
struct
in_ifaddr
*
ifa
=
in_dev
->
ifa_list
;
if
(
ifa
!=
NULL
)
{
...
...
@@ -247,7 +258,7 @@ isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
}
}
skb
=
isdn_net_ciscohdlck_alloc_skb
(
lp
,
4
+
14
);
skb
=
isdn_net_ciscohdlck_alloc_skb
(
idev
,
4
+
14
);
if
(
!
skb
)
return
;
...
...
@@ -265,13 +276,13 @@ isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
p
+=
put_u32
(
p
,
mask
);
// netmask
p
+=
put_u16
(
p
,
0
);
// unused
isdn_net_write_super
(
lp
,
skb
);
isdn_net_write_super
(
idev
,
skb
);
}
static
void
isdn_net_ciscohdlck_slarp_in
(
isdn_net_
local
*
lp
,
struct
sk_buff
*
skb
)
isdn_net_ciscohdlck_slarp_in
(
isdn_net_
dev
*
idev
,
struct
sk_buff
*
skb
)
{
isdn_net_
dev
*
idev
=
lp
->
netdev
;
isdn_net_
local
*
mlp
=
idev
->
mlp
;
unsigned
char
*
p
;
int
period
;
u32
code
;
...
...
@@ -288,8 +299,8 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
switch
(
code
)
{
case
CISCO_SLARP_REQUEST
:
lp
->
cisco_yourseq
=
0
;
isdn_net_ciscohdlck_slarp_send_reply
(
lp
);
m
lp
->
cisco_yourseq
=
0
;
isdn_net_ciscohdlck_slarp_send_reply
(
idev
);
break
;
case
CISCO_SLARP_REPLY
:
addr
=
ntohl
(
*
(
u32
*
)
p
);
...
...
@@ -315,30 +326,29 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
HIPQUAD
(
addr
),
HIPQUAD
(
mask
));
break
;
case
CISCO_SLARP_KEEPALIVE
:
period
=
(
int
)((
jiffies
-
lp
->
cisco_last_slarp_in
period
=
(
int
)((
jiffies
-
m
lp
->
cisco_last_slarp_in
+
HZ
/
2
-
1
)
/
HZ
);
if
(
lp
->
cisco_debserint
&&
(
period
!=
lp
->
cisco_keepalive_period
)
&&
lp
->
cisco_last_slarp_in
)
{
if
(
m
lp
->
cisco_debserint
&&
(
period
!=
m
lp
->
cisco_keepalive_period
)
&&
m
lp
->
cisco_last_slarp_in
)
{
printk
(
KERN_DEBUG
"%s: Keepalive period mismatch - "
"is %d but should be %d.
\n
"
,
idev
->
name
,
period
,
lp
->
cisco_keepalive_period
);
idev
->
name
,
period
,
m
lp
->
cisco_keepalive_period
);
}
lp
->
cisco_last_slarp_in
=
jiffies
;
m
lp
->
cisco_last_slarp_in
=
jiffies
;
p
+=
get_u32
(
p
,
&
my_seq
);
p
+=
get_u32
(
p
,
&
your_seq
);
p
+=
get_u16
(
p
,
&
unused
);
lp
->
cisco_yourseq
=
my_seq
;
lp
->
cisco_mineseen
=
your_seq
;
m
lp
->
cisco_yourseq
=
my_seq
;
m
lp
->
cisco_mineseen
=
your_seq
;
break
;
}
}
static
void
isdn_ciscohdlck_receive
(
isdn_net_
dev
*
idev
,
isdn_net_local
*
olp
,
isdn_ciscohdlck_receive
(
isdn_net_
local
*
lp
,
isdn_net_dev
*
idev
,
struct
sk_buff
*
skb
)
{
isdn_net_local
*
lp
=
&
idev
->
local
;
unsigned
char
*
p
;
u8
addr
;
u8
ctrl
;
...
...
@@ -362,7 +372,7 @@ isdn_ciscohdlck_receive(isdn_net_dev *idev, isdn_net_local *olp,
switch
(
type
)
{
case
CISCO_TYPE_SLARP
:
isdn_net_ciscohdlck_slarp_in
(
lp
,
skb
);
isdn_net_ciscohdlck_slarp_in
(
idev
,
skb
);
goto
out_free
;
case
CISCO_TYPE_CDP
:
if
(
lp
->
cisco_debserint
)
...
...
@@ -371,7 +381,7 @@ isdn_ciscohdlck_receive(isdn_net_dev *idev, isdn_net_local *olp,
goto
out_free
;
default:
/* no special cisco protocol */
i
sdn_net_reset_huptimer
(
idev
,
olp
->
netdev
)
;
i
dev
->
huptimer
=
0
;
skb
->
protocol
=
htons
(
type
);
netif_rx
(
skb
);
return
;
...
...
@@ -396,6 +406,7 @@ isdn_ciscohdlck_header(struct sk_buff *skb, struct net_device *dev,
}
struct
isdn_netif_ops
ciscohdlck_ops
=
{
.
hard_start_xmit
=
isdn_net_start_xmit
,
.
hard_header
=
isdn_ciscohdlck_header
,
.
do_ioctl
=
isdn_ciscohdlck_dev_ioctl
,
.
flags
=
IFF_NOARP
|
IFF_POINTOPOINT
,
...
...
drivers/isdn/i4l/isdn_common.c
View file @
994b6e06
...
...
@@ -46,8 +46,7 @@ struct isdn_slot {
unsigned
long
obytes
;
/* Statistics outgoing bytes */
struct
isdn_v110
iv110
;
/* For V.110 */
int
m_idx
;
/* Index for mdm.... */
isdn_net_dev
*
rx_netdev
;
/* rx netdev-pointers */
isdn_net_dev
*
st_netdev
;
/* stat netdev-pointers */
isdn_net_dev
*
idev
;
/* pointer to isdn_net_dev */
};
static
struct
isdn_slot
slot
[
ISDN_MAX_CHANNELS
];
...
...
@@ -508,7 +507,7 @@ isdn_status_callback(isdn_ctrl * c)
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
->
local
.
msn
);
strcpy
(
cmd
.
parm
.
setup
.
eazmsn
,
p
->
mlp
->
msn
);
isdn_slot_command
(
i
,
ISDN_CMD_ACCEPTD
,
&
cmd
);
retval
=
1
;
break
;
...
...
@@ -1010,19 +1009,6 @@ static int
isdn_status_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
uint
cmd
,
ulong
arg
)
{
int
ret
;
union
iocpar
{
char
name
[
10
];
char
bname
[
22
];
isdn_ioctl_struct
iocts
;
isdn_net_ioctl_phone
phone
;
isdn_net_ioctl_cfg
cfg
;
}
iocpar
;
#define name iocpar.name
#define bname iocpar.bname
#define iocts iocpar.iocts
#define phone iocpar.phone
#define cfg iocpar.cfg
switch
(
cmd
)
{
case
IIOCGETDVR
:
...
...
@@ -1044,26 +1030,11 @@ isdn_status_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
}
else
return
-
EINVAL
;
break
;
#ifdef CONFIG_NETDEVICES
case
IIOCNETGPN
:
/* Get peer phone number of a connected
* isdn network interface */
if
(
arg
)
{
if
(
copy_from_user
((
char
*
)
&
phone
,
(
char
*
)
arg
,
sizeof
(
phone
)))
return
-
EFAULT
;
return
isdn_net_getpeer
(
&
phone
,
(
isdn_net_ioctl_phone
*
)
arg
);
}
else
return
-
EINVAL
;
#endif
return
isdn_net_ioctl
(
inode
,
file
,
cmd
,
arg
);
default:
return
-
EINVAL
;
}
#undef name
#undef bname
#undef iocts
#undef phone
#undef cfg
}
static
struct
file_operations
isdn_status_fops
=
...
...
@@ -1221,19 +1192,15 @@ isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
int
ret
;
int
i
;
char
*
p
;
union
iocpar
{
char
name
[
10
];
/* save stack space */
union
{
char
bname
[
20
];
isdn_ioctl_struct
iocts
;
isdn_net_ioctl_phone
phone
;
isdn_net_ioctl_cfg
cfg
;
}
iocpar
;
#define name iocpar.name
#define bname iocpar.bname
#define iocts iocpar.iocts
#define
phone iocpar.phon
e
#define cfg iocpar.cfg
#define
bname iocpar.bnam
e
/*
* isdn net devices manage lots of configuration variables as linked lists.
* Those lists must only be manipulated from user space. Some of the ioctl's
...
...
@@ -1242,134 +1209,19 @@ isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
* are serialized by means of a semaphore.
*/
switch
(
cmd
)
{
case
IIOCNETDWRSET
:
printk
(
KERN_INFO
"INFO: ISDN_DW_ABC_EXTENSION not enabled
\n
"
);
return
(
-
EINVAL
);
case
IIOCNETLCR
:
printk
(
KERN_INFO
"INFO: ISDN_ABC_LCR_SUPPORT not enabled
\n
"
);
return
-
ENODEV
;
#ifdef CONFIG_NETDEVICES
case
IIOCNETAIF
:
/* Add a network-interface */
if
(
copy_from_user
(
name
,
(
char
*
)
arg
,
sizeof
(
name
)
-
1
))
return
-
EFAULT
;
name
[
sizeof
(
name
)
-
1
]
=
0
;
ret
=
down_interruptible
(
&
dev
->
sem
);
if
(
ret
)
return
ret
;
ret
=
isdn_net_new
(
name
,
NULL
);
up
(
&
dev
->
sem
);
return
ret
;
case
IIOCNETASL
:
/* Add a slave to a network-interface */
if
(
copy_from_user
(
bname
,
(
char
*
)
arg
,
sizeof
(
bname
)
-
1
))
return
-
EFAULT
;
bname
[
sizeof
(
bname
)
-
1
]
=
0
;
ret
=
down_interruptible
(
&
dev
->
sem
);
if
(
ret
)
return
ret
;
ret
=
isdn_net_newslave
(
bname
);
up
(
&
dev
->
sem
);
return
ret
;
case
IIOCNETDIF
:
/* Delete a network-interface */
if
(
arg
)
{
if
(
copy_from_user
(
name
,
(
char
*
)
arg
,
sizeof
(
name
)))
return
-
EFAULT
;
ret
=
down_interruptible
(
&
dev
->
sem
);
if
(
ret
)
return
ret
;
ret
=
isdn_net_rm
(
name
);
up
(
&
dev
->
sem
);
return
ret
;
}
else
return
-
EINVAL
;
case
IIOCNETSCF
:
/* Set configurable parameters of a network-interface */
if
(
arg
)
{
if
(
copy_from_user
((
char
*
)
&
cfg
,
(
char
*
)
arg
,
sizeof
(
cfg
)))
return
-
EFAULT
;
return
isdn_net_setcfg
(
&
cfg
);
}
else
return
-
EINVAL
;
case
IIOCNETGCF
:
/* Get configurable parameters of a network-interface */
if
(
arg
)
{
if
(
copy_from_user
((
char
*
)
&
cfg
,
(
char
*
)
arg
,
sizeof
(
cfg
)))
return
-
EFAULT
;
if
(
!
(
ret
=
isdn_net_getcfg
(
&
cfg
)))
{
if
(
copy_to_user
((
char
*
)
arg
,
(
char
*
)
&
cfg
,
sizeof
(
cfg
)))
return
-
EFAULT
;
}
return
ret
;
}
else
return
-
EINVAL
;
case
IIOCNETANM
:
/* Add a phone-number to a network-interface */
if
(
arg
)
{
if
(
copy_from_user
((
char
*
)
&
phone
,
(
char
*
)
arg
,
sizeof
(
phone
)))
return
-
EFAULT
;
ret
=
down_interruptible
(
&
dev
->
sem
);
if
(
ret
)
return
ret
;
ret
=
isdn_net_addphone
(
&
phone
);
up
(
&
dev
->
sem
);
return
ret
;
}
else
return
-
EINVAL
;
case
IIOCNETGNM
:
/* Get list of phone-numbers of a network-interface */
if
(
arg
)
{
if
(
copy_from_user
((
char
*
)
&
phone
,
(
char
*
)
arg
,
sizeof
(
phone
)))
return
-
EFAULT
;
ret
=
down_interruptible
(
&
dev
->
sem
);
if
(
ret
)
return
ret
;
ret
=
isdn_net_getphones
(
&
phone
,
(
char
*
)
arg
);
up
(
&
dev
->
sem
);
return
ret
;
}
else
return
-
EINVAL
;
case
IIOCNETDNM
:
/* Delete a phone-number of a network-interface */
if
(
arg
)
{
if
(
copy_from_user
((
char
*
)
&
phone
,
(
char
*
)
arg
,
sizeof
(
phone
)))
return
-
EFAULT
;
ret
=
down_interruptible
(
&
dev
->
sem
);
if
(
ret
)
return
ret
;
ret
=
isdn_net_delphone
(
&
phone
);
up
(
&
dev
->
sem
);
return
ret
;
}
else
return
-
EINVAL
;
case
IIOCNETDIL
:
/* Force dialing of a network-interface */
if
(
arg
)
{
if
(
copy_from_user
(
name
,
(
char
*
)
arg
,
sizeof
(
name
)))
return
-
EFAULT
;
return
isdn_net_force_dial
(
name
);
}
else
return
-
EINVAL
;
#ifdef CONFIG_ISDN_PPP
case
IIOCNETALN
:
if
(
!
arg
)
return
-
EINVAL
;
if
(
copy_from_user
(
name
,
(
char
*
)
arg
,
sizeof
(
name
)))
return
-
EFAULT
;
return
isdn_ppp_dial_slave
(
name
);
case
IIOCNETDLN
:
if
(
!
arg
)
return
-
EINVAL
;
if
(
copy_from_user
(
name
,
(
char
*
)
arg
,
sizeof
(
name
)))
return
-
EFAULT
;
return
isdn_ppp_hangup_slave
(
name
);
#endif
case
IIOCNETHUP
:
/* Force hangup of a network-interface */
if
(
!
arg
)
return
-
EINVAL
;
if
(
copy_from_user
(
name
,
(
char
*
)
arg
,
sizeof
(
name
)))
return
-
EFAULT
;
return
isdn_net_force_hangup
(
name
);
break
;
#endif
/* CONFIG_NETDEVICES */
return
isdn_net_ioctl
(
inode
,
file
,
cmd
,
arg
);
case
IIOCSETVER
:
dev
->
net_verbose
=
arg
;
printk
(
KERN_INFO
"isdn: Verbose-Level is %d
\n
"
,
dev
->
net_verbose
);
...
...
@@ -1577,12 +1429,8 @@ isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
}
else
return
-
EINVAL
;
}
#undef name
#undef bname
#undef iocts
#undef phone
#undef cfg
#undef bname
}
static
struct
file_operations
isdn_ctrl_fops
=
...
...
@@ -2218,35 +2066,19 @@ isdn_slot_num(int sl)
}
void
isdn_slot_set_rx_netdev
(
int
sl
,
isdn_net_dev
*
nd
)
{
BUG_ON
(
sl
<
0
);
slot
[
sl
].
rx_netdev
=
nd
;
}
isdn_net_dev
*
isdn_slot_rx_netdev
(
int
sl
)
{
BUG_ON
(
sl
<
0
);
return
slot
[
sl
].
rx_netdev
;
}
void
isdn_slot_set_st_netdev
(
int
sl
,
isdn_net_dev
*
nd
)
isdn_slot_set_idev
(
int
sl
,
isdn_net_dev
*
idev
)
{
BUG_ON
(
sl
<
0
);
slot
[
sl
].
st_netdev
=
nd
;
slot
[
sl
].
idev
=
idev
;
}
isdn_net_dev
*
isdn_slot_
st_net
dev
(
int
sl
)
isdn_slot_
i
dev
(
int
sl
)
{
BUG_ON
(
sl
<
0
);
return
slot
[
sl
].
st_net
dev
;
return
slot
[
sl
].
i
dev
;
}
int
...
...
@@ -2430,7 +2262,7 @@ static int __init isdn_init(void)
printk
(
"
\n
"
);
#endif
isdn_info_update
();
isdn_net_init
_module
();
isdn_net_init
();
return
0
;
err_tty_modem:
...
...
@@ -2456,8 +2288,7 @@ static void __exit isdn_exit(void)
#endif
save_flags
(
flags
);
cli
();
if
(
isdn_net_rmall
()
<
0
)
BUG
();
isdn_net_exit
();
isdn_tty_exit
();
if
(
unregister_chrdev
(
ISDN_MAJOR
,
"isdn"
))
...
...
drivers/isdn/i4l/isdn_common.h
View file @
994b6e06
...
...
@@ -22,11 +22,11 @@
#undef ISDN_DEBUG_MODEM_DUMP
#undef ISDN_DEBUG_MODEM_VOICE
#undef ISDN_DEBUG_AT
#
undef
ISDN_DEBUG_NET_DUMP
#
undef
ISDN_DEBUG_NET_DIAL
#
undef
ISDN_DEBUG_NET_ICALL
#
undef
ISDN_DEBUG_STATCALLB
#
undef
ISDN_DEBUG_COMMAND
#
define
ISDN_DEBUG_NET_DUMP
#
define
ISDN_DEBUG_NET_DIAL
#
define
ISDN_DEBUG_NET_ICALL
#
define
ISDN_DEBUG_STATCALLB
#
define
ISDN_DEBUG_COMMAND
#ifdef ISDN_DEBUG_NET_DIAL
#define dbg_net_dial(arg...) printk(KERN_DEBUG arg)
...
...
@@ -52,6 +52,8 @@ do { printk(KERN_WARNING "ISDN Bug at %s:%d\n", __FILE__, __LINE__); \
#define HERE printk("%s:%d (%s)\n", __FILE__, __LINE__, __FUNCTION__)
extern
struct
list_head
isdn_net_devs
;
/* Prototypes */
extern
void
isdn_MOD_INC_USE_COUNT
(
void
);
extern
void
isdn_MOD_DEC_USE_COUNT
(
void
);
...
...
@@ -82,8 +84,6 @@ struct dial_info {
unsigned
char
*
phone
;
};
extern
struct
list_head
isdn_net_devs
;
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_all_eaz
(
int
slot
);
...
...
@@ -100,8 +100,6 @@ extern void isdn_slot_set_usage(int slot, int usage);
extern
char
*
isdn_slot_num
(
int
slot
);
extern
int
isdn_slot_m_idx
(
int
slot
);
extern
void
isdn_slot_set_m_idx
(
int
slot
,
int
midx
);
extern
void
isdn_slot_set_rx_netdev
(
int
sl
,
isdn_net_dev
*
nd
);
extern
void
isdn_slot_set_st_netdev
(
int
sl
,
isdn_net_dev
*
nd
);
extern
isdn_net_dev
*
isdn_slot_rx_netdev
(
int
sl
);
extern
isdn_net_dev
*
isdn_slot_st_netdev
(
int
sl
);
extern
void
isdn_slot_set_idev
(
int
sl
,
isdn_net_dev
*
);
extern
isdn_net_dev
*
isdn_slot_idev
(
int
sl
);
extern
int
isdn_hard_header_len
(
void
);
drivers/isdn/i4l/isdn_concap.c
View file @
994b6e06
...
...
@@ -39,7 +39,8 @@
*/
int
isdn_concap_dl_data_req
(
struct
concap_proto
*
concap
,
struct
sk_buff
*
skb
)
static
int
isdn_concap_dl_data_req
(
struct
concap_proto
*
concap
,
struct
sk_buff
*
skb
)
{
struct
net_device
*
ndev
=
concap
->
net_dev
;
isdn_net_dev
*
nd
=
((
isdn_net_local
*
)
ndev
->
priv
)
->
netdev
;
...
...
@@ -58,7 +59,8 @@ int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
}
int
isdn_concap_dl_connect_req
(
struct
concap_proto
*
concap
)
static
int
isdn_concap_dl_connect_req
(
struct
concap_proto
*
concap
)
{
struct
net_device
*
ndev
=
concap
->
net_dev
;
isdn_net_local
*
lp
=
(
isdn_net_local
*
)
ndev
->
priv
;
...
...
@@ -71,7 +73,8 @@ int isdn_concap_dl_connect_req(struct concap_proto *concap)
return
ret
;
}
int
isdn_concap_dl_disconn_req
(
struct
concap_proto
*
concap
)
static
int
isdn_concap_dl_disconn_req
(
struct
concap_proto
*
concap
)
{
IX25DEBUG
(
"isdn_concap_dl_disconn_req: %s
\n
"
,
concap
->
net_dev
->
name
);
...
...
@@ -98,7 +101,8 @@ struct concap_device_ops isdn_concap_demand_dial_dops = {
this sourcefile does not need to include any protocol specific header
files. For now:
*/
struct
concap_proto
*
isdn_concap_new
(
int
encap
)
struct
concap_proto
*
isdn_concap_new
(
int
encap
)
{
switch
(
encap
)
{
case
ISDN_NET_ENCAP_X25IFACE
:
...
...
@@ -158,7 +162,7 @@ isdn_x25_disconnected(isdn_net_local *lp)
pops
->
disconn_ind
(
cprot
);
}
int
static
int
isdn_x25_start_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
{
/* At this point hard_start_xmit() passes control to the encapsulation
...
...
@@ -237,13 +241,8 @@ isdn_x25_cleanup(isdn_net_dev *p)
restore_flags
(
flags
);
}
void
isdn_x25_realrm
(
isdn_net_dev
*
p
)
{
if
(
p
->
cprot
&&
p
->
cprot
->
pops
)
p
->
cprot
->
pops
->
proto_del
(
p
->
cprot
);
}
struct
isdn_netif_ops
isdn_x25_ops
=
{
.
hard_start_xmit
=
isdn_x25_start_xmit
,
.
flags
=
IFF_NOARP
|
IFF_POINTOPOINT
,
.
type
=
ARPHRD_X25
,
.
receive
=
isdn_x25_receive
,
...
...
drivers/isdn/i4l/isdn_concap.h
View file @
994b6e06
...
...
@@ -12,18 +12,4 @@ extern struct concap_device_ops isdn_concap_demand_dial_dops;
struct
concap_proto
*
isdn_concap_new
(
int
);
#ifdef CONFIG_ISDN_X25
extern
struct
isdn_netif_ops
isdn_x25_ops
;
int
isdn_x25_start_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
);
#else
static
inline
int
isdn_x25_start_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
{
return
0
;
}
#endif
drivers/isdn/i4l/isdn_fsm.c
0 → 100644
View file @
994b6e06
/* $Id: fsm.c,v 1.14.6.4 2001/09/23 22:24:47 kai Exp $
*
* Finite state machine
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
* by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* Thanks to Jan den Ouden
* Fritz Elfert
*
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include "isdn_fsm.h"
int
fsm_new
(
struct
fsm
*
fsm
)
{
int
i
;
int
size
=
sizeof
(
fsm_fn
)
*
fsm
->
st_cnt
*
fsm
->
ev_cnt
;
fsm
->
jumpmatrix
=
kmalloc
(
size
,
GFP_KERNEL
);
if
(
!
fsm
->
jumpmatrix
)
return
-
ENOMEM
;
memset
(
fsm
->
jumpmatrix
,
0
,
size
);
for
(
i
=
0
;
i
<
fsm
->
fn_cnt
;
i
++
)
{
if
(
fsm
->
fn_tbl
[
i
].
st
>=
fsm
->
st_cnt
||
fsm
->
fn_tbl
[
i
].
ev
>=
fsm
->
ev_cnt
)
{
printk
(
KERN_ERR
"FsmNew Error line %d st(%d/%d) ev(%d/%d)
\n
"
,
i
,
fsm
->
fn_tbl
[
i
].
st
,
fsm
->
st_cnt
,
fsm
->
fn_tbl
[
i
].
ev
,
fsm
->
ev_cnt
);
continue
;
}
fsm
->
jumpmatrix
[
fsm
->
st_cnt
*
fsm
->
fn_tbl
[
i
].
ev
+
fsm
->
fn_tbl
[
i
].
st
]
=
fsm
->
fn_tbl
[
i
].
routine
;
}
return
0
;
}
void
fsm_free
(
struct
fsm
*
fsm
)
{
kfree
(
fsm
->
jumpmatrix
);
}
int
fsm_event
(
struct
fsm_inst
*
fi
,
int
event
,
void
*
arg
)
{
fsm_fn
fn
;
if
(
fi
->
state
>=
fi
->
fsm
->
st_cnt
||
event
>=
fi
->
fsm
->
ev_cnt
)
{
printk
(
KERN_ERR
"FsmEvent Error st(%d/%d) ev(%d/%d)
\n
"
,
fi
->
state
,
fi
->
fsm
->
st_cnt
,
event
,
fi
->
fsm
->
ev_cnt
);
return
-
EINVAL
;
}
fn
=
fi
->
fsm
->
jumpmatrix
[
fi
->
fsm
->
st_cnt
*
event
+
fi
->
state
];
if
(
!
fn
)
{
if
(
fi
->
debug
)
fi
->
printdebug
(
fi
,
"State %s Event %s no routine"
,
fi
->
fsm
->
st_str
[
fi
->
state
],
fi
->
fsm
->
ev_str
[
event
]);
return
-
ESRCH
;
}
if
(
fi
->
debug
)
fi
->
printdebug
(
fi
,
"State %s Event %s"
,
fi
->
fsm
->
st_str
[
fi
->
state
],
fi
->
fsm
->
ev_str
[
event
]);
fn
(
fi
,
event
,
arg
);
return
0
;
}
void
fsm_change_state
(
struct
fsm_inst
*
fi
,
int
newstate
)
{
fi
->
state
=
newstate
;
if
(
fi
->
debug
)
fi
->
printdebug
(
fi
,
"ChangeState %s"
,
fi
->
fsm
->
st_str
[
newstate
]);
}
#if 0
static void
FsmExpireTimer(struct FsmTimer *ft)
{
#if FSM_TIMER_DEBUG
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft);
#endif
FsmEvent(ft->fi, ft->event, ft->arg);
}
void
FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
{
ft->fi = fi;
ft->tl.function = (void *) FsmExpireTimer;
ft->tl.data = (long) ft;
#if FSM_TIMER_DEBUG
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmInitTimer %lx", (long) ft);
#endif
init_timer(&ft->tl);
}
void
FsmDelTimer(struct FsmTimer *ft, int where)
{
#if FSM_TIMER_DEBUG
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmDelTimer %lx %d", (long) ft, where);
#endif
del_timer(&ft->tl);
}
int
FsmAddTimer(struct FsmTimer *ft,
int millisec, int event, void *arg, int where)
{
#if FSM_TIMER_DEBUG
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmAddTimer %lx %d %d",
(long) ft, millisec, where);
#endif
if (timer_pending(&ft->tl)) {
printk(KERN_WARNING "FsmAddTimer: timer already active!\n");
ft->fi->printdebug(ft->fi, "FsmAddTimer already active!");
return -1;
}
init_timer(&ft->tl);
ft->event = event;
ft->arg = arg;
ft->tl.expires = jiffies + (millisec * HZ) / 1000;
add_timer(&ft->tl);
return 0;
}
void
FsmRestartTimer(struct FsmTimer *ft,
int millisec, int event, void *arg, int where)
{
#if FSM_TIMER_DEBUG
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmRestartTimer %lx %d %d",
(long) ft, millisec, where);
#endif
if (timer_pending(&ft->tl))
del_timer(&ft->tl);
init_timer(&ft->tl);
ft->event = event;
ft->arg = arg;
ft->tl.expires = jiffies + (millisec * HZ) / 1000;
add_timer(&ft->tl);
}
#endif
drivers/isdn/i4l/isdn_fsm.h
0 → 100644
View file @
994b6e06
/* $Id: fsm.h,v 1.3.2.2 2001/09/23 22:24:47 kai Exp $
*
* Finite state machine
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
* by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#ifndef __FSM_H__
#define __FSM_H__
#include <linux/timer.h>
struct
fsm_inst
;
typedef
void
(
*
fsm_fn
)(
struct
fsm_inst
*
,
int
,
void
*
);
struct
fsm
{
fsm_fn
*
jumpmatrix
;
int
st_cnt
,
ev_cnt
,
fn_cnt
;
char
**
st_str
,
**
ev_str
;
struct
fsm_node
*
fn_tbl
;
};
struct
fsm_inst
{
struct
fsm
*
fsm
;
int
state
;
int
debug
;
void
*
userdata
;
int
userint
;
void
(
*
printdebug
)
(
struct
fsm_inst
*
,
char
*
,
...);
};
struct
fsm_node
{
int
st
,
ev
;
void
(
*
routine
)
(
struct
fsm_inst
*
,
int
,
void
*
);
};
struct
fsm_timer
{
struct
fsm_inst
*
fi
;
struct
timer_list
tl
;
int
ev
;
void
*
arg
;
};
int
fsm_new
(
struct
fsm
*
fsm
);
void
fsm_free
(
struct
fsm
*
fsm
);
int
fsm_event
(
struct
fsm_inst
*
fi
,
int
event
,
void
*
arg
);
void
fsm_change_state
(
struct
fsm_inst
*
fi
,
int
newstate
);
void
fsm_init_timer
(
struct
fsm_inst
*
fi
,
struct
fsm_timer
*
ft
);
int
fsm_add_timer
(
struct
fsm_timer
*
ft
,
int
timeout
,
int
event
);
void
fsm_mod_timer
(
struct
fsm_timer
*
ft
,
int
timeout
,
int
event
);
void
fsm_del_timer
(
struct
fsm_timer
*
ft
);
#endif
drivers/isdn/i4l/isdn_net.c
View file @
994b6e06
...
...
@@ -33,34 +33,6 @@
#include "isdn_concap.h"
#include "isdn_ciscohdlck.h"
enum
{
ST_NULL
,
ST_OUT_WAIT_DCONN
,
ST_OUT_WAIT_BCONN
,
ST_IN_WAIT_DCONN
,
ST_IN_WAIT_BCONN
,
ST_ACTIVE
,
ST_WAIT_BEFORE_CB
,
};
enum
{
ST_CHARGE_NULL
,
ST_CHARGE_GOT_CINF
,
/* got a first charge info */
ST_CHARGE_HAVE_CINT
,
/* got a second chare info and thus the timing */
};
/* keep clear of ISDN_CMD_* and ISDN_STAT_* */
enum
{
EV_NET_DIAL
=
0x200
,
EV_NET_TIMER_IN_DCONN
=
0x201
,
EV_NET_TIMER_IN_BCONN
=
0x202
,
EV_NET_TIMER_OUT_DCONN
=
0x203
,
EV_NET_TIMER_OUT_BCONN
=
0x204
,
EV_NET_TIMER_CB
=
0x205
,
};
LIST_HEAD
(
isdn_net_devs
);
/* Linked list of isdn_net_dev's */
/*
* Outline of new tbusy handling:
*
...
...
@@ -90,30 +62,20 @@ LIST_HEAD(isdn_net_devs); /* Linked list of isdn_net_dev's */
/*
* Find out if the netdevice has been ifup-ed yet.
* For slaves, look at the corresponding master.
*/
static
__inline__
int
isdn_net_device_started
(
isdn_net_dev
*
n
)
static
inline
int
isdn_net_device_started
(
isdn_net_dev
*
idev
)
{
isdn_net_local
*
lp
=
&
n
->
local
;
struct
net_device
*
dev
;
if
(
lp
->
master
)
dev
=
lp
->
master
;
else
dev
=
&
n
->
dev
;
return
netif_running
(
dev
);
return
netif_running
(
&
idev
->
mlp
->
dev
);
}
/*
* stop the network -> net_device queue.
* For slaves, stop the corresponding master interface.
*/
static
__inline__
void
isdn_net_device_stop_queue
(
isdn_net_local
*
lp
)
static
inline
void
isdn_net_dev_stop_queue
(
isdn_net_dev
*
idev
)
{
if
(
lp
->
master
)
netif_stop_queue
(
lp
->
master
);
else
netif_stop_queue
(
&
lp
->
netdev
->
dev
);
netif_stop_queue
(
&
idev
->
mlp
->
dev
);
}
/*
...
...
@@ -121,104 +83,73 @@ static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp)
* master or slave) is busy. It's busy iff all (master and slave)
* queues are busy
*/
static
__inline__
int
isdn_net_device_busy
(
isdn_net_local
*
lp
)
static
inline
int
isdn_net_device_busy
(
isdn_net_dev
*
idev
)
{
isdn_net_local
*
nlp
;
isdn_net_dev
*
nd
;
isdn_net_local
*
mlp
=
idev
->
mlp
;
unsigned
long
flags
;
int
retval
=
1
;
if
(
!
isdn_net_
lp_busy
(
lp
))
if
(
!
isdn_net_
dev_busy
(
idev
))
return
0
;
if
(
lp
->
master
)
nd
=
((
isdn_net_local
*
)
lp
->
master
->
priv
)
->
netdev
;
else
nd
=
lp
->
netdev
;
spin_lock_irqsave
(
&
nd
->
queue_lock
,
flags
);
nlp
=
lp
->
next
;
while
(
nlp
!=
lp
)
{
if
(
!
isdn_net_lp_busy
(
nlp
))
{
spin_unlock_irqrestore
(
&
nd
->
queue_lock
,
flags
);
return
0
;
spin_lock_irqsave
(
&
mlp
->
online_lock
,
flags
);
list_for_each_entry
(
idev
,
&
mlp
->
online
,
online
)
{
if
(
!
isdn_net_dev_busy
(
idev
))
{
retval
=
0
;
break
;
}
nlp
=
nlp
->
next
;
}
spin_unlock_irqrestore
(
&
nd
->
queu
e_lock
,
flags
);
return
1
;
spin_unlock_irqrestore
(
&
mlp
->
onlin
e_lock
,
flags
);
return
retval
;
}
static
__inline__
void
isdn_net_inc_frame_cnt
(
isdn_net_local
*
lp
)
static
inline
void
isdn_net_inc_frame_cnt
(
isdn_net_dev
*
idev
)
{
atomic_inc
(
&
lp
->
frame_cnt
);
if
(
isdn_net_device_busy
(
lp
))
isdn_net_dev
ice_stop_queue
(
lp
);
atomic_inc
(
&
idev
->
frame_cnt
);
if
(
isdn_net_device_busy
(
idev
))
isdn_net_dev
_stop_queue
(
idev
);
}
static
__inline__
void
isdn_net_dec_frame_cnt
(
isdn_net_local
*
lp
)
static
inline
void
isdn_net_dec_frame_cnt
(
isdn_net_dev
*
idev
)
{
atomic_dec
(
&
lp
->
frame_cnt
);
atomic_dec
(
&
idev
->
frame_cnt
);
if
(
!
(
isdn_net_device_busy
(
lp
)))
{
if
(
!
skb_queue_empty
(
&
lp
->
super_tx_queue
))
{
schedule_work
(
&
lp
->
tqueue
);
}
else
{
isdn_net_device_wake_queue
(
lp
);
}
if
(
!
isdn_net_device_busy
(
idev
))
{
if
(
!
skb_queue_empty
(
&
idev
->
super_tx_queue
))
tasklet_schedule
(
&
idev
->
tlet
);
else
isdn_net_dev_wake_queue
(
idev
);
}
}
static
__inline__
void
isdn_net_zero_frame_cnt
(
isdn_net_local
*
lp
)
static
inline
void
isdn_net_zero_frame_cnt
(
isdn_net_dev
*
idev
)
{
atomic_set
(
&
lp
->
frame_cnt
,
0
);
atomic_set
(
&
idev
->
frame_cnt
,
0
);
}
/* For 2.2.x we leave the transmitter busy timeout at 2 secs, just
* to be safe.
* For 2.3.x we push it up to 20 secs, because call establishment
* (in particular callback) may take such a long time, and we
* don't want confusing messages in the log. However, there is a slight
* possibility that this large timeout will break other things like MPPP,
* which might rely on the tx timeout. If so, we'll find out this way...
*/
/* Prototypes */
#define ISDN_NET_TX_TIMEOUT (20*HZ)
int
isdn_net_handle_event
(
isdn_net_dev
*
idev
,
int
pr
,
void
*
arg
);
char
*
isdn_net_revision
=
"$Revision: 1.140.6.11 $"
;
static
struct
isdn_netif_ops
*
netif_ops
[
ISDN_NET_ENCAP_NR
];
/* A packet has successfully been sent out. */
int
register_isdn_netif
(
int
encap
,
struct
isdn_netif_ops
*
ops
)
isdn_net_bsent
(
isdn_net_dev
*
idev
,
isdn_ctrl
*
c
)
{
if
(
encap
<
0
||
encap
>=
ISDN_NET_ENCAP_NR
)
return
-
EINVAL
;
isdn_net_local
*
mlp
=
idev
->
mlp
;
if
(
netif_ops
[
encap
])
return
-
EBUSY
;
netif_ops
[
encap
]
=
ops
;
return
0
;
}
int
isdn_net_online
(
isdn_net_dev
*
idev
)
{
return
idev
->
dialstate
==
ST_ACTIVE
;
isdn_net_dec_frame_cnt
(
idev
);
mlp
->
stats
.
tx_packets
++
;
mlp
->
stats
.
tx_bytes
+=
c
->
parm
.
length
;
return
1
;
}
/* Prototypes */
static
int
isdn_net_force_dial_lp
(
isdn_net_local
*
);
static
int
isdn_net_start_xmit
(
struct
sk_buff
*
,
struct
net_device
*
);
static
void
do_dialout
(
isdn_net_local
*
lp
);
static
int
isdn_net_set_encap
(
isdn_net_dev
*
p
,
int
encap
);
static
int
isdn_net_handle_event
(
isdn_net_local
*
lp
,
int
pr
,
void
*
arg
);
char
*
isdn_net_revision
=
"$Revision: 1.140.6.11 $"
;
/*
* Code for raw-networking over ISDN
*/
static
void
isdn_net_unreachable
(
struct
net_device
*
dev
,
struct
sk_buff
*
skb
,
char
*
reason
)
{
...
...
@@ -232,1970 +163,437 @@ isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason)
dst_link_failure
(
skb
);
}
/* Open/initialize the board. */
static
int
isdn_net_open
(
struct
net_device
*
dev
)
{
isdn_net_local
*
lp
=
dev
->
priv
;
int
retval
=
0
;
if
(
!
lp
->
ops
)
return
-
ENODEV
;
if
(
lp
->
ops
->
open
)
retval
=
lp
->
ops
->
open
(
lp
);
if
(
!
retval
)
return
retval
;
netif_start_queue
(
dev
);
isdn_MOD_INC_USE_COUNT
();
return
0
;
}
/*
* unbind a net-interface (resets interface after an error)
*/
static
void
isdn_net_
unbind_channel
(
isdn_net_local
*
lp
)
isdn_net_
log_skb
(
struct
sk_buff
*
skb
,
isdn_net_dev
*
idev
)
{
isdn_net_dev
*
idev
=
lp
->
netdev
;
ulong
flags
;
save_flags
(
flags
);
cli
();
if
(
lp
->
ops
->
unbind
)
lp
->
ops
->
unbind
(
lp
);
skb_queue_purge
(
&
lp
->
super_tx_queue
);
unsigned
char
*
p
=
skb
->
nh
.
raw
;
/* hopefully, this was set correctly */
unsigned
short
proto
=
ntohs
(
skb
->
protocol
);
int
data_ofs
;
struct
ip_ports
{
unsigned
short
source
;
unsigned
short
dest
;
}
*
ipp
;
char
addinfo
[
100
];
if
(
!
lp
->
master
)
{
/* reset only master device */
/* Moral equivalent of dev_purge_queues():
BEWARE! This chunk of code cannot be called from hardware
interrupt handler. I hope it is true. --ANK
*/
qdisc_reset
(
lp
->
netdev
->
dev
.
qdisc
);
}
idev
->
dialstate
=
ST_NULL
;
if
(
idev
->
isdn_slot
>=
0
)
{
isdn_slot_set_rx_netdev
(
idev
->
isdn_slot
,
NULL
);
isdn_slot_set_st_netdev
(
idev
->
isdn_slot
,
NULL
);
isdn_slot_free
(
idev
->
isdn_slot
,
ISDN_USAGE_NET
);
data_ofs
=
((
p
[
0
]
&
15
)
*
4
);
switch
(
proto
)
{
case
ETH_P_IP
:
switch
(
p
[
9
])
{
case
IPPROTO_ICMP
:
strcpy
(
addinfo
,
"ICMP"
);
break
;
case
IPPROTO_TCP
:
case
IPPROTO_UDP
:
ipp
=
(
struct
ip_ports
*
)
(
&
p
[
data_ofs
]);
sprintf
(
addinfo
,
"%s, port: %d -> %d"
,
p
[
9
]
==
IPPROTO_TCP
?
"TCP"
:
"UDP"
,
ntohs
(
ipp
->
source
),
ntohs
(
ipp
->
dest
));
break
;
default:
sprintf
(
addinfo
,
"type %d"
,
p
[
9
]);
}
idev
->
isdn_slot
=
-
1
;
printk
(
KERN_INFO
"OPEN: %u.%u.%u.%u -> %u.%u.%u.%u %s
\n
"
,
restore_flags
(
flags
);
NIPQUAD
(
*
(
u32
*
)(
p
+
12
)),
NIPQUAD
(
*
(
u32
*
)(
p
+
16
)),
addinfo
);
break
;
case
ETH_P_ARP
:
printk
(
KERN_INFO
"OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d
\n
"
,
NIPQUAD
(
*
(
u32
*
)(
p
+
14
)),
NIPQUAD
(
*
(
u32
*
)(
p
+
24
)));
break
;
default:
printk
(
KERN_INFO
"OPEN: unknown proto %#x
\n
"
,
proto
);
}
}
/*
* Assign an ISDN-channel to a net-interface
* this function is used to send supervisory data, i.e. data which was
* not received from the network layer, but e.g. frames from ipppd, CCP
* reset frames etc.
*/
static
int
isdn_net_
bind_channel
(
isdn_net_local
*
lp
,
int
idx
)
void
isdn_net_
write_super
(
isdn_net_dev
*
idev
,
struct
sk_buff
*
skb
)
{
isdn_net_dev
*
idev
=
lp
->
netdev
;
int
retval
=
0
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
idev
->
isdn_slot
=
idx
;
isdn_slot_set_rx_netdev
(
idev
->
isdn_slot
,
lp
->
netdev
);
isdn_slot_set_st_netdev
(
idev
->
isdn_slot
,
lp
->
netdev
);
if
(
lp
->
ops
->
bind
)
retval
=
lp
->
ops
->
bind
(
lp
);
if
(
in_irq
())
{
// we can't grab the lock from irq context,
// so we just queue the packet
skb_queue_tail
(
&
idev
->
super_tx_queue
,
skb
);
if
(
retval
<
0
)
isdn_net_unbind_channel
(
lp
);
tasklet_schedule
(
&
idev
->
tlet
);
return
;
}
restore_flags
(
flags
);
return
retval
;
spin_lock_bh
(
&
idev
->
xmit_lock
);
if
(
!
isdn_net_dev_busy
(
idev
))
{
isdn_net_writebuf_skb
(
idev
,
skb
);
}
else
{
skb_queue_tail
(
&
idev
->
super_tx_queue
,
skb
);
}
spin_unlock_bh
(
&
idev
->
xmit_lock
);
}
/*
* Perform auto-hangup for net-interfaces.
*
* auto-hangup:
* Increment idle-counter (this counter is reset on any incoming or
* outgoing packet), if counter exceeds configured limit either do a
* hangup immediately or - if configured - wait until just before the next
* charge-info.
* all frames sent from the (net) LL to a HL driver should go via this function
* it's serialized by the caller holding the idev->xmit_lock spinlock
*/
static
void
isdn_net_hup_timer
(
unsigned
long
data
)
void
isdn_net_writebuf_skb
(
isdn_net_dev
*
idev
,
struct
sk_buff
*
skb
)
{
isdn_net_dev
*
idev
=
(
isdn_net_dev
*
)
data
;
isdn_net_local
*
lp
=
&
idev
->
local
;
isdn_net_local
*
mlp
=
idev
->
mlp
;
int
ret
;
int
len
=
skb
->
len
;
/* save len */
if
(
!
isdn_net_online
(
idev
))
{
/* before obtaining the lock the caller should have checked that
the lp isn't busy */
if
(
isdn_net_dev_busy
(
idev
))
{
isdn_BUG
();
return
;
goto
error
;
}
dbg_net_dial
(
"%s: huptimer %d, onhtime %d, chargetime %ld, chargeint %d
\n
"
,
l
->
name
,
l
->
huptimer
,
l
->
onhtime
,
l
->
chargetime
,
l
->
chargeint
);
if
(
lp
->
onhtime
==
0
)
return
;
if
(
idev
->
huptimer
++
<=
lp
->
onhtime
)
goto
mod_timer
;
if
((
lp
->
hupflags
&
(
ISDN_MANCHARGE
|
ISDN_CHARGEHUP
))
==
(
ISDN_MANCHARGE
|
ISDN_CHARGEHUP
))
{
while
(
time_after
(
jiffies
,
idev
->
chargetime
+
idev
->
chargeint
))
idev
->
chargetime
+=
idev
->
chargeint
;
if
(
time_after
(
jiffies
,
idev
->
chargetime
+
idev
->
chargeint
-
2
*
HZ
))
{
if
(
idev
->
outgoing
||
lp
->
hupflags
&
ISDN_INHUP
)
{
isdn_net_hangup
(
idev
);
return
;
}
}
}
else
if
(
idev
->
outgoing
)
{
if
(
lp
->
hupflags
&
ISDN_CHARGEHUP
)
{
if
(
idev
->
charge_state
!=
ST_CHARGE_HAVE_CINT
)
{
dbg_net_dial
(
"%s: did not get CINT
\n
"
,
lp
->
name
);
isdn_net_hangup
(
idev
);
return
;
}
else
if
(
time_after
(
jiffies
,
idev
->
chargetime
+
idev
->
chargeint
))
{
dbg_net_dial
(
"%s: chtime = %lu, chint = %d
\n
"
,
lp
->
name
,
lp
->
chargetime
,
lp
->
chargeint
);
isdn_net_hangup
(
idev
);
return
;
if
(
!
isdn_net_online
(
idev
))
{
isdn_BUG
();
goto
error
;
}
ret
=
isdn_slot_write
(
idev
->
isdn_slot
,
skb
);
if
(
ret
!=
len
)
{
/* we should never get here */
printk
(
KERN_WARNING
"%s: HL driver queue full
\n
"
,
idev
->
name
);
goto
error
;
}
}
else
if
(
lp
->
hupflags
&
ISDN_INHUP
)
{
isdn_net_hangup
(
idev
);
idev
->
transcount
+=
len
;
isdn_net_inc_frame_cnt
(
idev
);
return
;
}
mod_timer:
mod_timer
(
&
idev
->
hup_timer
,
idev
->
hup_timer
.
expires
+
HZ
);
}
static
void
isdn_net_lp_disconnected
(
isdn_net_local
*
lp
)
{
isdn_net_rm_from_bundle
(
lp
)
;
error:
dev_kfree_skb
(
skb
);
mlp
->
stats
.
tx_errors
++
;
}
static
void
isdn_net_connected
(
isdn_net_local
*
lp
)
static
void
isdn_net_dial_slave
(
isdn_net_local
*
mlp
)
{
isdn_net_dev
*
idev
=
lp
->
netdev
;
isdn_net_dev
*
idev
;
idev
->
dialstate
=
ST_ACTIVE
;
idev
->
hup_timer
.
expires
=
jiffies
+
HZ
;
add_timer
(
&
idev
->
hup_timer
);
if
(
lp
->
p_encap
!=
ISDN_NET_ENCAP_SYNCPPP
)
{
if
(
lp
->
master
)
{
/* is lp a slave? */
isdn_net_dev
*
nd
=
((
isdn_net_local
*
)
lp
->
master
->
priv
)
->
netdev
;
isdn_net_add_to_bundle
(
nd
,
lp
);
list_for_each_entry
(
idev
,
&
mlp
->
slaves
,
slaves
)
{
if
(
!
isdn_net_bound
(
idev
))
{
isdn_net_dial
(
idev
);
break
;
}
}
printk
(
KERN_INFO
"isdn_net: %s connected
\n
"
,
idev
->
name
);
/* If first Chargeinfo comes before B-Channel connect,
* we correct the timestamp here.
*/
idev
->
chargetime
=
jiffies
;
/* reset dial-timeout */
idev
->
dialstarted
=
0
;
idev
->
dialwait_timer
=
0
;
idev
->
transcount
=
0
;
idev
->
cps
=
0
;
idev
->
last_jiffies
=
jiffies
;
if
(
lp
->
ops
->
connected
)
lp
->
ops
->
connected
(
lp
);
else
isdn_net_device_wake_queue
(
lp
);
}
/*
* Handle status-messages from ISDN-interfacecard.
* This function is called from within the main-status-dispatcher
* isdn_status_callback, which itself is called from the low-level driver.
* Return: 1 = Event handled, 0 = not for us or unknown Event.
* Based on cps-calculation, check if device is overloaded.
* If so, and if a slave exists, trigger dialing for it.
* If any slave is online, deliver packets using a simple round robin
* scheme.
*
* Return: 0 on success, !0 on failure.
*/
int
isdn_net_stat_callback
(
int
idx
,
isdn_ctrl
*
c
)
{
isdn_net_dev
*
p
=
isdn_slot_st_netdev
(
idx
);
isdn_net_local
*
lp
;
int
cmd
=
c
->
command
;
if
(
!
p
)
{
HERE
;
return
0
;
}
lp
=
&
p
->
local
;
return
isdn_net_handle_event
(
lp
,
cmd
,
c
);
}
static
void
isdn_net_
dial_timer
(
unsigned
long
data
)
int
isdn_net_
start_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
ndev
)
{
isdn_net_dev
*
idev
=
(
isdn_net_dev
*
)
data
;
isdn_net_dev
*
idev
;
isdn_net_local
*
mlp
=
ndev
->
priv
;
isdn_net_handle_event
(
&
idev
->
local
,
idev
->
dial_event
,
NULL
);
}
/* Initiate dialout. Set phone-number-pointer to first number
* of interface.
*/
static
void
init_dialout
(
isdn_net_local
*
lp
)
{
isdn_net_dev
*
idev
=
lp
->
netdev
;
ndev
->
trans_start
=
jiffies
;
idev
->
dial
=
0
;
if
(
list_empty
(
&
mlp
->
online
))
return
isdn_net_autodial
(
skb
,
ndev
);
i
f
(
lp
->
dialtimeout
>
0
&&
(
idev
->
dialstarted
==
0
||
time_after
(
jiffies
,
idev
->
dialstarted
+
lp
->
dialtimeout
+
lp
->
dialwait
)))
{
idev
->
dialstarted
=
jiffies
;
idev
->
dialwait_timer
=
0
;
i
dev
=
isdn_net_get_locked_dev
(
mlp
);
if
(
!
idev
)
{
printk
(
KERN_WARNING
"%s: all channels busy - requeuing!
\n
"
,
ndev
->
name
);
netif_stop_queue
(
ndev
)
;
return
1
;
}
lp
->
dialretry
=
0
;
do_dialout
(
lp
);
}
/* we have our idev locked from now on */
/* Setup interface, dial current phone-number, switch to next number.
* If list of phone-numbers is exhausted, increment
* retry-counter.
*/
static
void
do_dialout
(
isdn_net_local
*
lp
)
{
isdn_net_dev
*
idev
=
lp
->
netdev
;
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
,
};
if
(
ISDN_NET_DIALMODE
(
*
lp
)
==
ISDN_NET_DM_OFF
)
return
;
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
++
==
idev
->
dial
)
goto
found
;
}
/* otherwise start in front */
phone
=
list_entry
(
lp
->
phone
[
1
].
next
,
struct
isdn_net_phone
,
list
);
idev
->
dial
=
0
;
lp
->
dialretry
++
;
isdn_net_writebuf_skb
(
idev
,
skb
);
spin_unlock_bh
(
&
idev
->
xmit_lock
);
found:
idev
->
dial
++
;
dial
.
phone
=
phone
->
num
;
spin_unlock_irqrestore
(
&
lp
->
lock
,
flags
);
if
(
lp
->
dialretry
>
lp
->
dialmax
)
{
if
(
lp
->
dialtimeout
==
0
)
{
idev
->
dialwait_timer
=
jiffies
+
lp
->
dialwait
;
idev
->
dialstarted
=
0
;
}
isdn_net_hangup
(
idev
);
return
;
}
if
(
lp
->
dialtimeout
>
0
&&
time_after
(
jiffies
,
idev
->
dialstarted
+
lp
->
dialtimeout
))
{
idev
->
dialwait_timer
=
jiffies
+
lp
->
dialwait
;
idev
->
dialstarted
=
0
;
isdn_net_hangup
(
idev
);
return
;
}
/*
* Switch to next number or back to start if at end of list.
/* the following stuff is here for backwards compatibility.
* in future, start-up and hangup of slaves (based on current load)
* should move to userspace and get based on an overall cps
* calculation
*/
isdn_slot_dial
(
idev
->
isdn_slot
,
&
dial
);
idev
->
huptimer
=
0
;
idev
->
outgoing
=
1
;
if
(
idev
->
chargeint
)
idev
->
charge_state
=
ST_CHARGE_HAVE_CINT
;
else
idev
->
charge_state
=
ST_CHARGE_NULL
;
if
(
lp
->
cbdelay
&&
(
lp
->
flags
&
ISDN_NET_CBOUT
))
{
idev
->
dial_timer
.
expires
=
jiffies
+
lp
->
cbdelay
;
idev
->
dial_event
=
EV_NET_TIMER_CB
;
}
else
{
idev
->
dial_timer
.
expires
=
jiffies
+
10
*
HZ
;
idev
->
dial_event
=
EV_NET_TIMER_OUT_DCONN
;
if
(
jiffies
!=
idev
->
last_jiffies
)
{
idev
->
cps
=
idev
->
transcount
*
HZ
/
(
jiffies
-
idev
->
last_jiffies
);
idev
->
last_jiffies
=
jiffies
;
idev
->
transcount
=
0
;
}
idev
->
dialstate
=
ST_OUT_WAIT_DCONN
;
add_timer
(
&
idev
->
dial_timer
);
}
if
(
dev
->
net_verbose
>
3
)
printk
(
KERN_DEBUG
"%s: %d bogocps
\n
"
,
idev
->
name
,
idev
->
cps
);
/* For EV_NET_DIAL, returns 1 if timer callback is needed
* For ISDN_STAT_*, returns 1 if event was for us
*/
static
int
isdn_net_handle_event
(
isdn_net_local
*
lp
,
int
pr
,
void
*
arg
)
{
isdn_net_dev
*
idev
=
lp
->
netdev
;
isdn_ctrl
*
c
=
arg
;
isdn_ctrl
cmd
;
dbg_net_dial
(
"%s: dialstate=%d pr=%#x
\n
"
,
lp
->
name
,
lp
->
dialstate
,
pr
);
switch
(
idev
->
dialstate
)
{
case
ST_ACTIVE
:
switch
(
pr
)
{
case
ISDN_STAT_BSENT
:
/* A packet has successfully been sent out */
isdn_net_dec_frame_cnt
(
lp
);
lp
->
stats
.
tx_packets
++
;
lp
->
stats
.
tx_bytes
+=
c
->
parm
.
length
;
return
1
;
case
ISDN_STAT_DHUP
:
if
(
lp
->
ops
->
disconnected
)
lp
->
ops
->
disconnected
(
lp
);
isdn_net_lp_disconnected
(
lp
);
isdn_slot_all_eaz
(
idev
->
isdn_slot
);
printk
(
KERN_INFO
"%s: remote hangup
\n
"
,
idev
->
name
);
printk
(
KERN_INFO
"%s: Chargesum is %d
\n
"
,
idev
->
name
,
idev
->
charge
);
isdn_net_unbind_channel
(
lp
);
return
1
;
case
ISDN_STAT_CINF
:
/* Charge-info from TelCo. Calculate interval between
* charge-infos and set timestamp for last info for
* usage by isdn_net_autohup()
*/
idev
->
charge
++
;
switch
(
idev
->
charge_state
)
{
case
ST_CHARGE_NULL
:
idev
->
charge_state
=
ST_CHARGE_GOT_CINF
;
break
;
case
ST_CHARGE_GOT_CINF
:
idev
->
charge_state
=
ST_CHARGE_HAVE_CINT
;
/* fall through */
case
ST_CHARGE_HAVE_CINT
:
idev
->
chargeint
=
jiffies
-
idev
->
chargetime
-
2
*
HZ
;
break
;
}
idev
->
chargetime
=
jiffies
;
dbg_net_dial
(
"%s: got CINF
\n
"
,
lp
->
name
);
return
1
;
}
break
;
case
ST_OUT_WAIT_DCONN
:
switch
(
pr
)
{
case
EV_NET_TIMER_OUT_DCONN
:
/* try again */
do_dialout
(
lp
);
return
1
;
case
EV_NET_TIMER_CB
:
/* Remote does callback. Hangup after cbdelay,
* then wait for incoming call */
printk
(
KERN_INFO
"%s: hangup waiting for callback ...
\n
"
,
idev
->
name
);
isdn_net_hangup
(
idev
);
return
1
;
case
ISDN_STAT_DCONN
:
/* Got D-Channel-Connect, send B-Channel-request */
del_timer
(
&
idev
->
dial_timer
);
idev
->
dialstate
=
ST_OUT_WAIT_BCONN
;
isdn_slot_command
(
idev
->
isdn_slot
,
ISDN_CMD_ACCEPTB
,
&
cmd
);
idev
->
dial_timer
.
expires
=
jiffies
+
10
*
HZ
;
idev
->
dial_event
=
EV_NET_TIMER_OUT_BCONN
;
add_timer
(
&
idev
->
dial_timer
);
return
1
;
case
ISDN_STAT_DHUP
:
del_timer
(
&
idev
->
dial_timer
);
isdn_slot_all_eaz
(
idev
->
isdn_slot
);
printk
(
KERN_INFO
"%s: remote hangup
\n
"
,
idev
->
name
);
isdn_net_unbind_channel
(
lp
);
return
1
;
}
break
;
case
ST_OUT_WAIT_BCONN
:
switch
(
pr
)
{
case
EV_NET_TIMER_OUT_BCONN
:
/* try again */
do_dialout
(
lp
);
return
1
;
case
ISDN_STAT_BCONN
:
del_timer
(
&
idev
->
dial_timer
);
isdn_slot_set_usage
(
idev
->
isdn_slot
,
isdn_slot_usage
(
idev
->
isdn_slot
)
|
ISDN_USAGE_OUTGOING
);
isdn_net_connected
(
lp
);
return
1
;
case
ISDN_STAT_DHUP
:
del_timer
(
&
idev
->
dial_timer
);
isdn_slot_all_eaz
(
idev
->
isdn_slot
);
printk
(
KERN_INFO
"%s: remote hangup
\n
"
,
idev
->
name
);
isdn_net_unbind_channel
(
lp
);
return
1
;
}
break
;
case
ST_IN_WAIT_DCONN
:
switch
(
pr
)
{
case
EV_NET_TIMER_IN_DCONN
:
isdn_net_hangup
(
idev
);
return
1
;
case
ISDN_STAT_DCONN
:
del_timer
(
&
idev
->
dial_timer
);
idev
->
dialstate
=
ST_IN_WAIT_BCONN
;
isdn_slot_command
(
idev
->
isdn_slot
,
ISDN_CMD_ACCEPTB
,
&
cmd
);
idev
->
dial_timer
.
expires
=
jiffies
+
10
*
HZ
;
idev
->
dial_event
=
EV_NET_TIMER_IN_BCONN
;
add_timer
(
&
idev
->
dial_timer
);
return
1
;
case
ISDN_STAT_DHUP
:
del_timer
(
&
idev
->
dial_timer
);
isdn_slot_all_eaz
(
idev
->
isdn_slot
);
printk
(
KERN_INFO
"%s: remote hangup
\n
"
,
idev
->
name
);
isdn_net_unbind_channel
(
lp
);
return
1
;
}
break
;
case
ST_IN_WAIT_BCONN
:
switch
(
pr
)
{
case
EV_NET_TIMER_IN_BCONN
:
isdn_net_hangup
(
idev
);
break
;
case
ISDN_STAT_BCONN
:
del_timer
(
&
idev
->
dial_timer
);
isdn_slot_set_rx_netdev
(
idev
->
isdn_slot
,
idev
);
isdn_net_connected
(
lp
);
return
1
;
case
ISDN_STAT_DHUP
:
del_timer
(
&
idev
->
dial_timer
);
isdn_slot_all_eaz
(
idev
->
isdn_slot
);
printk
(
KERN_INFO
"%s: remote hangup
\n
"
,
idev
->
name
);
isdn_net_unbind_channel
(
lp
);
return
1
;
if
(
idev
->
cps
>
mlp
->
triggercps
)
{
if
(
!
idev
->
sqfull
)
{
/* First time overload: set timestamp only */
idev
->
sqfull
=
1
;
idev
->
sqfull_stamp
=
jiffies
;
}
else
{
/* subsequent overload: if slavedelay exceeded, start dialing */
if
(
time_after
(
jiffies
,
idev
->
sqfull_stamp
+
mlp
->
slavedelay
))
{
isdn_net_dial_slave
(
mlp
);
}
break
;
case
ST_WAIT_BEFORE_CB
:
switch
(
pr
)
{
case
EV_NET_TIMER_CB
:
/* Callback Delay */
init_dialout
(
lp
);
return
1
;
}
break
;
default:
isdn_BUG
();
break
;
}
printk
(
"NOT HANDLED?
\n
"
);
return
0
;
}
/*
* Perform hangup for a net-interface.
*/
void
isdn_net_hangup
(
isdn_net_dev
*
idev
)
{
isdn_net_local
*
lp
=
&
idev
->
local
;
isdn_ctrl
cmd
;
del_timer_sync
(
&
idev
->
hup_timer
);
if
(
!
isdn_net_bound
(
idev
))
return
;
// FIXME ugly and recursive
if
(
lp
->
slave
!=
NULL
)
{
isdn_net_local
*
slp
=
(
isdn_net_local
*
)
lp
->
slave
->
priv
;
isdn_net_dev
*
sidev
=
slp
->
netdev
;
if
(
isdn_net_bound
(
sidev
))
{
printk
(
KERN_INFO
"isdn_net: hang up slave %s before %s
\n
"
,
sidev
->
name
,
idev
->
name
);
isdn_net_hangup
(
sidev
);
}
}
printk
(
KERN_INFO
"isdn_net: local hangup %s
\n
"
,
idev
->
name
);
if
(
lp
->
ops
->
disconnected
)
lp
->
ops
->
disconnected
(
lp
);
isdn_net_lp_disconnected
(
lp
);
isdn_slot_command
(
idev
->
isdn_slot
,
ISDN_CMD_HANGUP
,
&
cmd
);
printk
(
KERN_INFO
"%s: Chargesum is %d
\n
"
,
idev
->
name
,
idev
->
charge
);
isdn_slot_all_eaz
(
idev
->
isdn_slot
);
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
);
}
}
typedef
struct
{
unsigned
short
source
;
unsigned
short
dest
;
}
ip_ports
;
static
void
isdn_net_log_skb
(
struct
sk_buff
*
skb
,
isdn_net_local
*
lp
)
{
isdn_net_dev
*
idev
=
lp
->
netdev
;
u_char
*
p
=
skb
->
nh
.
raw
;
/* hopefully, this was set correctly */
unsigned
short
proto
=
ntohs
(
skb
->
protocol
);
int
data_ofs
;
ip_ports
*
ipp
;
char
addinfo
[
100
];
addinfo
[
0
]
=
'\0'
;
/* This check stolen from 2.1.72 dev_queue_xmit_nit() */
if
(
skb
->
nh
.
raw
<
skb
->
data
||
skb
->
nh
.
raw
>=
skb
->
tail
)
{
/* fall back to old isdn_net_log_packet method() */
char
*
buf
=
skb
->
data
;
printk
(
KERN_DEBUG
"isdn_net: protocol %04x is buggy, dev %s
\n
"
,
skb
->
protocol
,
idev
->
name
);
p
=
buf
;
proto
=
ETH_P_IP
;
switch
(
lp
->
p_encap
)
{
case
ISDN_NET_ENCAP_IPTYP
:
proto
=
ntohs
(
*
(
unsigned
short
*
)
&
buf
[
0
]);
p
=
&
buf
[
2
];
break
;
case
ISDN_NET_ENCAP_ETHER
:
proto
=
ntohs
(
*
(
unsigned
short
*
)
&
buf
[
12
]);
p
=
&
buf
[
14
];
break
;
case
ISDN_NET_ENCAP_CISCOHDLC
:
proto
=
ntohs
(
*
(
unsigned
short
*
)
&
buf
[
2
]);
p
=
&
buf
[
4
];
break
;
case
ISDN_NET_ENCAP_SYNCPPP
:
proto
=
ntohs
(
skb
->
protocol
);
p
=
&
buf
[
IPPP_MAX_HEADER
];
break
;
}
}
data_ofs
=
((
p
[
0
]
&
15
)
*
4
);
switch
(
proto
)
{
case
ETH_P_IP
:
switch
(
p
[
9
])
{
case
1
:
strcpy
(
addinfo
,
" ICMP"
);
break
;
case
2
:
strcpy
(
addinfo
,
" IGMP"
);
break
;
case
4
:
strcpy
(
addinfo
,
" IPIP"
);
break
;
case
6
:
ipp
=
(
ip_ports
*
)
(
&
p
[
data_ofs
]);
sprintf
(
addinfo
,
" TCP, port: %d -> %d"
,
ntohs
(
ipp
->
source
),
ntohs
(
ipp
->
dest
));
break
;
case
8
:
strcpy
(
addinfo
,
" EGP"
);
break
;
case
12
:
strcpy
(
addinfo
,
" PUP"
);
break
;
case
17
:
ipp
=
(
ip_ports
*
)
(
&
p
[
data_ofs
]);
sprintf
(
addinfo
,
" UDP, port: %d -> %d"
,
ntohs
(
ipp
->
source
),
ntohs
(
ipp
->
dest
));
break
;
case
22
:
strcpy
(
addinfo
,
" IDP"
);
break
;
}
printk
(
KERN_INFO
"OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s
\n
"
,
p
[
12
],
p
[
13
],
p
[
14
],
p
[
15
],
p
[
16
],
p
[
17
],
p
[
18
],
p
[
19
],
addinfo
);
break
;
case
ETH_P_ARP
:
printk
(
KERN_INFO
"OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d
\n
"
,
p
[
14
],
p
[
15
],
p
[
16
],
p
[
17
],
p
[
24
],
p
[
25
],
p
[
26
],
p
[
27
]);
break
;
}
}
/*
* this function is used to send supervisory data, i.e. data which was
* not received from the network layer, but e.g. frames from ipppd, CCP
* reset frames etc.
*/
void
isdn_net_write_super
(
isdn_net_local
*
lp
,
struct
sk_buff
*
skb
)
{
if
(
in_irq
())
{
// we can't grab the lock from irq context,
// so we just queue the packet
skb_queue_tail
(
&
lp
->
super_tx_queue
,
skb
);
schedule_work
(
&
lp
->
tqueue
);
return
;
}
spin_lock_bh
(
&
lp
->
xmit_lock
);
if
(
!
isdn_net_lp_busy
(
lp
))
{
isdn_net_writebuf_skb
(
lp
,
skb
);
}
else
{
skb_queue_tail
(
&
lp
->
super_tx_queue
,
skb
);
}
spin_unlock_bh
(
&
lp
->
xmit_lock
);
}
/*
* called from tq_immediate
*/
static
void
isdn_net_softint
(
void
*
private
)
{
isdn_net_local
*
lp
=
private
;
struct
sk_buff
*
skb
;
spin_lock_bh
(
&
lp
->
xmit_lock
);
while
(
!
isdn_net_lp_busy
(
lp
))
{
skb
=
skb_dequeue
(
&
lp
->
super_tx_queue
);
if
(
!
skb
)
break
;
isdn_net_writebuf_skb
(
lp
,
skb
);
}
spin_unlock_bh
(
&
lp
->
xmit_lock
);
}
/*
* all frames sent from the (net) LL to a HL driver should go via this function
* it's serialized by the caller holding the lp->xmit_lock spinlock
*/
void
isdn_net_writebuf_skb
(
isdn_net_local
*
lp
,
struct
sk_buff
*
skb
)
{
isdn_net_dev
*
idev
=
lp
->
netdev
;
int
ret
;
int
len
=
skb
->
len
;
/* save len */
/* before obtaining the lock the caller should have checked that
the lp isn't busy */
if
(
isdn_net_lp_busy
(
lp
))
{
isdn_BUG
();
goto
error
;
}
if
(
!
isdn_net_online
(
idev
))
{
isdn_BUG
();
goto
error
;
}
ret
=
isdn_slot_write
(
idev
->
isdn_slot
,
skb
);
if
(
ret
!=
len
)
{
/* we should never get here */
printk
(
KERN_WARNING
"%s: HL driver queue full
\n
"
,
idev
->
name
);
goto
error
;
}
idev
->
transcount
+=
len
;
isdn_net_inc_frame_cnt
(
lp
);
return
;
error:
dev_kfree_skb
(
skb
);
lp
->
stats
.
tx_errors
++
;
}
/*
* Helper function for isdn_net_start_xmit.
* When called, the connection is already established.
* Based on cps-calculation, check if device is overloaded.
* If so, and if a slave exists, trigger dialing for it.
* If any slave is online, deliver packets using a simple round robin
* scheme.
*
* Return: 0 on success, !0 on failure.
*/
static
int
isdn_net_xmit
(
struct
net_device
*
ndev
,
struct
sk_buff
*
skb
)
{
isdn_net_dev
*
nd
,
*
idev
;
isdn_net_local
*
slp
;
isdn_net_local
*
lp
=
ndev
->
priv
;
int
retv
=
0
;
if
(
lp
->
master
)
{
isdn_BUG
();
dev_kfree_skb
(
skb
);
return
0
;
}
/* For the other encaps the header has already been built */
if
(
lp
->
p_encap
==
ISDN_NET_ENCAP_SYNCPPP
)
{
return
isdn_ppp_xmit
(
skb
,
ndev
);
}
nd
=
((
isdn_net_local
*
)
ndev
->
priv
)
->
netdev
;
lp
=
isdn_net_get_locked_lp
(
nd
);
if
(
!
lp
)
{
printk
(
KERN_WARNING
"%s: all channels busy - requeuing!
\n
"
,
ndev
->
name
);
return
1
;
}
idev
=
lp
->
netdev
;
/* we have our lp locked from now on */
/* Reset hangup-timeout */
idev
->
huptimer
=
0
;
// FIXME?
isdn_net_writebuf_skb
(
lp
,
skb
);
spin_unlock_bh
(
&
lp
->
xmit_lock
);
/* the following stuff is here for backwards compatibility.
* in future, start-up and hangup of slaves (based on current load)
* should move to userspace and get based on an overall cps
* calculation
*/
if
(
jiffies
!=
idev
->
last_jiffies
)
{
idev
->
cps
=
idev
->
transcount
*
HZ
/
(
jiffies
-
idev
->
last_jiffies
);
idev
->
last_jiffies
=
jiffies
;
idev
->
transcount
=
0
;
}
if
(
dev
->
net_verbose
>
3
)
printk
(
KERN_DEBUG
"%s: %d bogocps
\n
"
,
idev
->
name
,
idev
->
cps
);
if
(
idev
->
cps
>
lp
->
triggercps
)
{
if
(
lp
->
slave
)
{
if
(
!
lp
->
sqfull
)
{
/* First time overload: set timestamp only */
lp
->
sqfull
=
1
;
lp
->
sqfull_stamp
=
jiffies
;
}
else
{
/* subsequent overload: if slavedelay exceeded, start dialing */
if
(
time_after
(
jiffies
,
lp
->
sqfull_stamp
+
lp
->
slavedelay
))
{
slp
=
lp
->
slave
->
priv
;
if
(
!
isdn_net_bound
(
slp
->
netdev
))
{
isdn_net_force_dial_lp
((
isdn_net_local
*
)
lp
->
slave
->
priv
);
}
}
}
}
}
else
{
if
(
lp
->
sqfull
&&
time_after
(
jiffies
,
lp
->
sqfull_stamp
+
lp
->
slavedelay
+
(
10
*
HZ
)))
{
lp
->
sqfull
=
0
;
}
else
{
if
(
idev
->
sqfull
&&
time_after
(
jiffies
,
idev
->
sqfull_stamp
+
mlp
->
slavedelay
+
10
*
HZ
))
{
idev
->
sqfull
=
0
;
}
/* this is a hack to allow auto-hangup for slaves on moderate loads */
nd
->
queue
=
&
nd
->
local
;
}
return
retv
;
}
static
void
isdn_net_adjust_hdr
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
{
isdn_net_local
*
lp
=
dev
->
priv
;
if
(
!
skb
)
return
;
if
(
lp
->
p_encap
==
ISDN_NET_ENCAP_ETHER
)
{
int
pullsize
=
(
ulong
)
skb
->
nh
.
raw
-
(
ulong
)
skb
->
data
-
ETH_HLEN
;
if
(
pullsize
>
0
)
{
printk
(
KERN_DEBUG
"isdn_net: Pull junk %d
\n
"
,
pullsize
);
skb_pull
(
skb
,
pullsize
);
}
}
}
void
isdn_net_tx_timeout
(
struct
net_device
*
ndev
)
{
isdn_net_local
*
lp
=
ndev
->
priv
;
isdn_net_dev
*
idev
=
lp
->
netdev
;
printk
(
KERN_WARNING
"isdn_tx_timeout dev %s %d
\n
"
,
ndev
->
name
,
idev
->
dialstate
);
netif_wake_queue
(
ndev
);
}
static
int
isdn_net_autodial
(
struct
sk_buff
*
skb
,
struct
net_device
*
ndev
)
{
isdn_net_local
*
lp
=
ndev
->
priv
;
isdn_net_dev
*
idev
=
lp
->
netdev
;
if
(
!
(
ISDN_NET_DIALMODE
(
*
lp
)
==
ISDN_NET_DM_AUTO
))
goto
discard
;
if
(
idev
->
dialwait_timer
<=
0
)
if
(
idev
->
dialstarted
>
0
&&
lp
->
dialtimeout
>
0
&&
time_before
(
jiffies
,
idev
->
dialstarted
+
lp
->
dialtimeout
+
lp
->
dialwait
))
idev
->
dialwait_timer
=
idev
->
dialstarted
+
lp
->
dialtimeout
+
lp
->
dialwait
;
if
(
idev
->
dialwait_timer
>
0
)
{
if
(
time_before
(
jiffies
,
idev
->
dialwait_timer
))
goto
discard
;
idev
->
dialwait_timer
=
0
;
}
if
(
isdn_net_force_dial_lp
(
lp
)
<
0
)
goto
discard
;
/* Log packet, which triggered dialing */
if
(
dev
->
net_verbose
)
isdn_net_log_skb
(
skb
,
lp
);
netif_stop_queue
(
ndev
);
return
1
;
discard:
isdn_net_unreachable
(
ndev
,
skb
,
"dial rejected"
);
dev_kfree_skb
(
skb
);
return
0
;
}
/*
* Try sending a packet.
* If this interface isn't connected to a ISDN-Channel, find a free channel,
* and start dialing.
*/
static
int
isdn_net_start_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
ndev
)
{
isdn_net_local
*
lp
=
ndev
->
priv
;
isdn_net_dev
*
idev
=
lp
->
netdev
;
int
retval
;
if
(
lp
->
p_encap
==
ISDN_NET_ENCAP_X25IFACE
)
return
isdn_x25_start_xmit
(
skb
,
ndev
);
/* auto-dialing xmit function */
isdn_net_adjust_hdr
(
skb
,
ndev
);
isdn_dumppkt
(
"S:"
,
skb
->
data
,
skb
->
len
,
40
);
if
(
!
isdn_net_bound
(
idev
))
return
isdn_net_autodial
(
skb
,
ndev
);
/* Device is bound to an ISDN channel */
ndev
->
trans_start
=
jiffies
;
if
(
idev
->
dialstate
!=
ST_ACTIVE
)
{
netif_stop_queue
(
ndev
);
return
1
;
}
/* ISDN connection is established, try sending */
retval
=
isdn_net_xmit
(
ndev
,
skb
);
if
(
retval
)
netif_stop_queue
(
ndev
);
return
retval
;
}
/*
* Shutdown a net-interface.
*/
static
int
isdn_net_close
(
struct
net_device
*
dev
)
{
struct
net_device
*
p
;
isdn_net_local
*
lp
=
dev
->
priv
;
if
(
lp
->
ops
->
close
)
lp
->
ops
->
close
(
lp
);
netif_stop_queue
(
dev
);
for
(
p
=
lp
->
slave
;
p
;
p
=
((
isdn_net_local
*
)
p
->
priv
)
->
slave
)
isdn_net_hangup
(
p
->
priv
);
isdn_net_hangup
(
dev
->
priv
);
isdn_MOD_DEC_USE_COUNT
();
return
0
;
}
/*
* Get statistics
*/
static
struct
net_device_stats
*
isdn_net_get_stats
(
struct
net_device
*
dev
)
{
isdn_net_local
*
lp
=
(
isdn_net_local
*
)
dev
->
priv
;
return
&
lp
->
stats
;
}
/*
* Got a packet from ISDN-Channel.
*/
static
void
isdn_net_receive
(
struct
net_device
*
ndev
,
struct
sk_buff
*
skb
)
{
isdn_net_local
*
lp
=
(
isdn_net_local
*
)
ndev
->
priv
;
isdn_net_dev
*
idev
=
lp
->
netdev
;
isdn_net_local
*
olp
=
lp
;
/* original 'lp' */
idev
->
transcount
+=
skb
->
len
;
lp
->
stats
.
rx_packets
++
;
lp
->
stats
.
rx_bytes
+=
skb
->
len
;
if
(
lp
->
master
)
{
/* Bundling: If device is a slave-device, deliver to master, also
* handle master's statistics and hangup-timeout
*/
ndev
=
lp
->
master
;
lp
=
(
isdn_net_local
*
)
ndev
->
priv
;
lp
->
stats
.
rx_packets
++
;
lp
->
stats
.
rx_bytes
+=
skb
->
len
;
}
skb
->
dev
=
ndev
;
skb
->
pkt_type
=
PACKET_HOST
;
skb
->
mac
.
raw
=
skb
->
data
;
isdn_dumppkt
(
"R:"
,
skb
->
data
,
skb
->
len
,
40
);
lp
->
ops
->
receive
(
lp
->
netdev
,
olp
,
skb
);
}
/*
* A packet arrived via ISDN. Search interface-chain for a corresponding
* interface. If found, deliver packet to receiver-function and return 1,
* else return 0.
*/
int
isdn_net_rcv_skb
(
int
idx
,
struct
sk_buff
*
skb
)
{
isdn_net_dev
*
idev
=
isdn_slot_rx_netdev
(
idx
);
if
(
!
idev
)
return
0
;
if
(
!
isdn_net_online
(
idev
))
return
0
;
isdn_net_receive
(
&
idev
->
dev
,
skb
);
return
0
;
}
/*
* Interface-setup. (just after registering a new interface)
*/
static
int
isdn_net_init
(
struct
net_device
*
ndev
)
{
/* Setup the generic properties */
ndev
->
mtu
=
1500
;
ndev
->
tx_queue_len
=
10
;
ndev
->
open
=
&
isdn_net_open
;
ndev
->
hard_start_xmit
=
&
isdn_net_start_xmit
;
ndev
->
hard_header_len
=
ETH_HLEN
+
isdn_hard_header_len
();
ndev
->
stop
=
&
isdn_net_close
;
ndev
->
get_stats
=
&
isdn_net_get_stats
;
return
0
;
}
static
int
isdn_net_do_callback
(
isdn_net_local
*
lp
)
{
isdn_net_dev
*
idev
=
lp
->
netdev
;
int
slot
;
/*
* Is the state MANUAL?
* If so, no callback can be made,
* so reject actively.
*/
if
(
ISDN_NET_DIALMODE
(
*
lp
)
==
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
,
lp
->
l2_proto
,
lp
->
l3_proto
,
idev
->
pre_device
,
idev
->
pre_channel
,
lp
->
msn
);
if
(
slot
<
0
)
goto
err
;
if
(
isdn_net_bind_channel
(
lp
,
slot
)
<
0
)
goto
err
;
/* Setup dialstate. */
idev
->
dial_timer
.
expires
=
jiffies
+
lp
->
cbdelay
;
idev
->
dial_event
=
EV_NET_TIMER_CB
;
add_timer
(
&
idev
->
dial_timer
);
idev
->
dialstate
=
ST_WAIT_BEFORE_CB
;
/* Initiate dialing by returning 2 or 4 */
return
(
lp
->
flags
&
ISDN_NET_CBHUP
)
?
2
:
4
;
err:
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
;
struct
list_head
*
l
;
struct
isdn_net_phone
*
n
;
ulong
flags
;
char
nr
[
32
];
char
*
my_eaz
;
int
retval
;
isdn_ctrl
cmd
;
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
*
lp
=
&
idev
->
local
;
/* check acceptable call types for DOV */
dbg_net_icall
(
"n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d
\n
"
,
lp
->
name
,
lp
->
msn
,
lp
->
flags
,
lp
->
dialstate
);
my_eaz
=
isdn_slot_map_eaz2msn
(
slot
,
lp
->
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
"
,
lp
->
pre_device
,
lp
->
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
(
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
))
{
spin_unlock_irqrestore
(
&
lp
->
lock
,
flags
);
goto
found
;
}
}
spin_unlock_irqrestore
(
&
lp
->
lock
,
flags
);
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
(
*
lp
)
==
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
;
}
/* 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
"
,
idev
->
name
);
printk
(
KERN_DEBUG
"master=%s
\n
"
,
mlp
->
netdev
->
name
);
if
(
isdn_net_bound
(
mlp
->
netdev
))
{
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
"
,
isdn_net_bound
(
mlp
->
netdev
));
if
(
!
isdn_net_bound
(
mlp
->
netdev
))
{
continue
;
}
}
if
(
lp
->
flags
&
ISDN_NET_CALLBACK
)
{
retval
=
isdn_net_do_callback
(
lp
);
restore_flags
(
flags
);
return
retval
;
}
printk
(
KERN_DEBUG
"%s: call from %s -> %s accepted
\n
"
,
idev
->
name
,
nr
,
eaz
);
strcpy
(
isdn_slot_num
(
idx
),
nr
);
isdn_slot_set_usage
(
idx
,
(
isdn_slot_usage
(
idx
)
&
ISDN_USAGE_EXCLUSIVE
)
|
ISDN_USAGE_NET
);
isdn_net_bind_channel
(
lp
,
idx
);
idev
->
outgoing
=
0
;
idev
->
huptimer
=
0
;
idev
->
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
(
idev
->
isdn_slot
,
ISDN_CMD_SETL2
,
&
cmd
);
cmd
.
arg
=
lp
->
l3_proto
<<
8
;
isdn_slot_command
(
idev
->
isdn_slot
,
ISDN_CMD_SETL3
,
&
cmd
);
idev
->
dial_timer
.
expires
=
jiffies
+
15
*
HZ
;
idev
->
dial_event
=
EV_NET_TIMER_IN_DCONN
;
add_timer
(
&
idev
->
dial_timer
);
idev
->
dialstate
=
ST_IN_WAIT_DCONN
;
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
;
}
/*
* Search list of net-interfaces for an interface with given name.
*/
isdn_net_dev
*
isdn_net_findif
(
char
*
name
)
{
struct
list_head
*
l
;
list_for_each
(
l
,
&
isdn_net_devs
)
{
isdn_net_dev
*
p
=
list_entry
(
l
,
isdn_net_dev
,
global_list
);
if
(
!
strcmp
(
p
->
name
,
name
))
return
p
;
}
return
NULL
;
}
/*
* Force a net-interface to dial out.
* This is called from the userlevel-routine below or
* from isdn_net_start_xmit().
*/
static
int
isdn_net_force_dial_lp
(
isdn_net_local
*
lp
)
{
isdn_net_dev
*
idev
=
lp
->
netdev
;
int
slot
;
unsigned
long
flags
;
if
(
isdn_net_bound
(
idev
))
return
-
EBUSY
;
save_flags
(
flags
);
cli
();
if
(
idev
->
exclusive
>=
0
)
slot
=
idev
->
exclusive
;
else
slot
=
isdn_get_free_slot
(
ISDN_USAGE_NET
,
lp
->
l2_proto
,
lp
->
l3_proto
,
idev
->
pre_device
,
idev
->
pre_channel
,
lp
->
msn
);
if
(
slot
<
0
)
goto
err
;
if
(
isdn_net_bind_channel
(
lp
,
slot
)
<
0
)
goto
err
;;
/* Initiate dialing */
restore_flags
(
flags
);
init_dialout
(
lp
);
return
0
;
err:
restore_flags
(
flags
);
return
-
EAGAIN
;
}
/*
* This is called from certain upper protocol layers (multilink ppp
* and x25iface encapsulation module) that want to initiate dialing
* themselves.
*/
int
isdn_net_dial_req
(
isdn_net_local
*
lp
)
{
/* is there a better error code? */
if
(
!
(
ISDN_NET_DIALMODE
(
*
lp
)
==
ISDN_NET_DM_AUTO
))
return
-
EBUSY
;
return
isdn_net_force_dial_lp
(
lp
);
}
/*
* Force a net-interface to dial out.
* This is always called from within userspace (ISDN_IOCTL_NET_DIAL).
*/
int
isdn_net_force_dial
(
char
*
name
)
{
isdn_net_dev
*
p
=
isdn_net_findif
(
name
);
if
(
!
p
)
return
-
ENODEV
;
return
(
isdn_net_force_dial_lp
(
&
p
->
local
));
}
/*
* Allocate a new network-interface and initialize its data structures.
*/
int
isdn_net_new
(
char
*
name
,
struct
net_device
*
master
)
{
int
retval
;
isdn_net_dev
*
netdev
;
/* Avoid creating an existing interface */
if
(
isdn_net_findif
(
name
))
{
printk
(
KERN_WARNING
"isdn_net: interface %s already exists
\n
"
,
name
);
return
-
EEXIST
;
}
if
(
!
(
netdev
=
kmalloc
(
sizeof
(
isdn_net_dev
),
GFP_KERNEL
)))
{
printk
(
KERN_WARNING
"isdn_net: Could not allocate net-device
\n
"
);
return
-
ENOMEM
;
}
memset
(
netdev
,
0
,
sizeof
(
isdn_net_dev
));
strcpy
(
netdev
->
name
,
name
);
strcpy
(
netdev
->
dev
.
name
,
name
);
netdev
->
dev
.
priv
=
&
netdev
->
local
;
netdev
->
dev
.
init
=
isdn_net_init
;
if
(
master
)
{
/* Device shall be a slave */
struct
net_device
*
p
=
(((
isdn_net_local
*
)
master
->
priv
)
->
slave
);
struct
net_device
*
q
=
master
;
netdev
->
local
.
master
=
master
;
/* Put device at end of slave-chain */
while
(
p
)
{
q
=
p
;
p
=
(((
isdn_net_local
*
)
p
->
priv
)
->
slave
);
}
((
isdn_net_local
*
)
q
->
priv
)
->
slave
=
&
(
netdev
->
dev
);
}
else
{
/* Device shall be a master */
/*
* Watchdog timer (currently) for master only.
*/
netdev
->
dev
.
tx_timeout
=
isdn_net_tx_timeout
;
netdev
->
dev
.
watchdog_timeo
=
ISDN_NET_TX_TIMEOUT
;
retval
=
register_netdev
(
&
netdev
->
dev
);
if
(
retval
)
{
printk
(
KERN_WARNING
"isdn_net: Could not register net-device
\n
"
);
kfree
(
netdev
);
return
retval
;
}
}
netdev
->
local
.
magic
=
ISDN_NET_MAGIC
;
netdev
->
queue
=
&
netdev
->
local
;
spin_lock_init
(
&
netdev
->
queue_lock
);
netdev
->
local
.
last
=
&
netdev
->
local
;
netdev
->
local
.
netdev
=
netdev
;
netdev
->
local
.
next
=
&
netdev
->
local
;
INIT_WORK
(
&
netdev
->
local
.
tqueue
,
isdn_net_softint
,
&
netdev
->
local
);
spin_lock_init
(
&
netdev
->
local
.
xmit_lock
);
netdev
->
isdn_slot
=
-
1
;
netdev
->
pre_device
=
-
1
;
netdev
->
pre_channel
=
-
1
;
netdev
->
exclusive
=
-
1
;
netdev
->
ppp_slot
=
-
1
;
netdev
->
pppbind
=
-
1
;
netdev
->
local
.
p_encap
=
-
1
;
skb_queue_head_init
(
&
netdev
->
local
.
super_tx_queue
);
netdev
->
local
.
l2_proto
=
ISDN_PROTO_L2_X75I
;
netdev
->
local
.
l3_proto
=
ISDN_PROTO_L3_TRANS
;
netdev
->
local
.
triggercps
=
6000
;
netdev
->
local
.
slavedelay
=
10
*
HZ
;
netdev
->
local
.
hupflags
=
ISDN_INHUP
;
/* Do hangup even on incoming calls */
netdev
->
local
.
onhtime
=
10
;
/* Default hangup-time for saving costs
of those who forget configuring this */
netdev
->
local
.
dialmax
=
1
;
netdev
->
local
.
flags
=
ISDN_NET_CBHUP
|
ISDN_NET_DM_MANUAL
;
/* Hangup before Callback, manual dial */
netdev
->
local
.
cbdelay
=
5
*
HZ
;
/* Wait 5 secs before Callback */
netdev
->
local
.
dialtimeout
=
-
1
;
/* Infinite Dial-Timeout */
netdev
->
local
.
dialwait
=
5
*
HZ
;
/* Wait 5 sec. after failed dial */
netdev
->
dialstarted
=
0
;
/* Jiffies of last dial-start */
netdev
->
dialwait_timer
=
0
;
/* Jiffies of earliest next dial-start */
init_timer
(
&
netdev
->
dial_timer
);
netdev
->
dial_timer
.
data
=
(
unsigned
long
)
netdev
;
netdev
->
dial_timer
.
function
=
isdn_net_dial_timer
;
init_timer
(
&
netdev
->
hup_timer
);
netdev
->
hup_timer
.
data
=
(
unsigned
long
)
netdev
;
netdev
->
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
]);
isdn_net_set_encap
(
netdev
,
ISDN_NET_ENCAP_RAWIP
);
/* Put into to netdev-chain */
list_add
(
&
netdev
->
global_list
,
&
isdn_net_devs
);
return
0
;
}
int
isdn_net_newslave
(
char
*
parm
)
{
char
*
p
=
strchr
(
parm
,
','
);
isdn_net_dev
*
m
;
/* Slave-Name MUST not be empty */
if
(
!
p
||
!
p
[
1
])
return
-
EINVAL
;
*
p
=
0
;
/* Master must already exist */
if
(
!
(
m
=
isdn_net_findif
(
parm
)))
return
-
ESRCH
;
/* Master must be a real interface, not a slave */
if
(
m
->
local
.
master
)
return
-
ENXIO
;
/* Master must not be started yet */
if
(
isdn_net_device_started
(
m
))
return
-
EBUSY
;
return
isdn_net_new
(
p
+
1
,
&
m
->
dev
);
}
static
int
isdn_net_set_encap
(
isdn_net_dev
*
p
,
int
encap
)
{
isdn_net_local
*
lp
=
&
p
->
local
;
int
retval
=
0
;
if
(
lp
->
p_encap
==
encap
){
/* nothing to do */
retval
=
0
;
goto
out
;
}
if
(
isdn_net_device_started
(
p
))
{
retval
=
-
EBUSY
;
goto
out
;
}
if
(
lp
->
ops
&&
lp
->
ops
->
cleanup
)
lp
->
ops
->
cleanup
(
lp
);
if
(
encap
<
0
||
encap
>=
ISDN_NET_ENCAP_NR
)
{
lp
->
p_encap
=
-
1
;
lp
->
ops
=
NULL
;
retval
=
-
EINVAL
;
goto
out
;
}
lp
->
p_encap
=
encap
;
lp
->
ops
=
netif_ops
[
encap
];
p
->
dev
.
hard_header
=
lp
->
ops
->
hard_header
;
p
->
dev
.
do_ioctl
=
lp
->
ops
->
do_ioctl
;
p
->
dev
.
flags
=
lp
->
ops
->
flags
;
p
->
dev
.
type
=
lp
->
ops
->
type
;
p
->
dev
.
addr_len
=
lp
->
ops
->
addr_len
;
if
(
lp
->
ops
->
init
)
retval
=
lp
->
ops
->
init
(
lp
);
if
(
retval
!=
0
)
{
lp
->
p_encap
=
-
1
;
lp
->
ops
=
NULL
;
}
out:
return
retval
;
}
static
int
isdn_net_bind
(
isdn_net_dev
*
idev
,
isdn_net_ioctl_cfg
*
cfg
)
{
isdn_net_local
*
lp
=
&
idev
->
local
;
int
i
,
retval
;
int
drvidx
=
-
1
;
int
chidx
=
-
1
;
char
drvid
[
25
];
strncpy
(
drvid
,
cfg
->
drvid
,
24
);
drvid
[
24
]
=
0
;
if
(
cfg
->
exclusive
&&
!
strlen
(
drvid
))
{
/* If we want to bind exclusively, need to specify drv/chan */
retval
=
-
ENODEV
;
goto
out
;
}
if
(
strlen
(
drvid
))
{
/* A bind has been requested ... */
char
*
c
=
strchr
(
drvid
,
','
);
if
(
!
c
)
{
retval
=
-
ENODEV
;
goto
out
;
}
/* The channel-number is appended to the driver-Id with a comma */
*
c
=
0
;
chidx
=
simple_strtol
(
c
+
1
,
NULL
,
10
);
for
(
i
=
0
;
i
<
ISDN_MAX_DRIVERS
;
i
++
)
{
/* Lookup driver-Id in array */
if
(
!
strcmp
(
dev
->
drvid
[
i
],
drvid
))
{
drvidx
=
i
;
break
;
}
}
if
(
drvidx
==
-
1
||
chidx
==
-
1
)
{
/* Either driver-Id or channel-number invalid */
retval
=
-
ENODEV
;
goto
out
;
}
}
if
(
cfg
->
exclusive
==
(
idev
->
exclusive
>=
0
)
&&
drvidx
==
idev
->
pre_device
&&
chidx
==
idev
->
pre_channel
)
{
/* no change */
retval
=
0
;
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
);
idev
->
exclusive
=
-
1
;
}
if
(
cfg
->
exclusive
)
{
/* If binding is exclusive, try to grab the channel */
idev
->
exclusive
=
isdn_get_free_slot
(
ISDN_USAGE_NET
,
lp
->
l2_proto
,
lp
->
l3_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
;
retval
=
0
;
out:
return
retval
;
}
/*
* Set interface-parameters.
* Always set all parameters, so the user-level application is responsible
* for not overwriting existing setups. It has to get the current
* setup first, if only selected parameters are to be changed.
*/
int
isdn_net_setcfg
(
isdn_net_ioctl_cfg
*
cfg
)
{
isdn_net_dev
*
idev
=
isdn_net_findif
(
cfg
->
name
);
isdn_net_local
*
lp
=
&
idev
->
local
;
ulong
features
;
int
i
,
retval
;
if
(
!
idev
)
{
retval
=
-
ENODEV
;
goto
out
;
}
/* See if any registered driver supports the features we want */
features
=
((
1
<<
cfg
->
l2_proto
)
<<
ISDN_FEATURE_L2_SHIFT
)
|
((
1
<<
cfg
->
l3_proto
)
<<
ISDN_FEATURE_L3_SHIFT
);
for
(
i
=
0
;
i
<
ISDN_MAX_DRIVERS
;
i
++
)
if
(
dev
->
drv
[
i
]
&&
(
dev
->
drv
[
i
]
->
interface
->
features
&
features
)
==
features
)
break
;
if
(
i
==
ISDN_MAX_DRIVERS
)
{
printk
(
KERN_WARNING
"isdn_net: No driver with selected features
\n
"
);
retval
=
-
ENODEV
;
goto
out
;
}
retval
=
isdn_net_set_encap
(
idev
,
cfg
->
p_encap
);
if
(
retval
)
goto
out
;
retval
=
isdn_net_bind
(
idev
,
cfg
);
if
(
retval
)
goto
out
;
strncpy
(
lp
->
msn
,
cfg
->
eaz
,
ISDN_MSNLEN
-
1
);
lp
->
msn
[
ISDN_MSNLEN
-
1
]
=
0
;
lp
->
onhtime
=
cfg
->
onhtime
;
idev
->
charge
=
cfg
->
charge
;
lp
->
l2_proto
=
cfg
->
l2_proto
;
lp
->
l3_proto
=
cfg
->
l3_proto
;
lp
->
cbdelay
=
cfg
->
cbdelay
*
HZ
/
5
;
lp
->
dialmax
=
cfg
->
dialmax
;
lp
->
triggercps
=
cfg
->
triggercps
;
lp
->
slavedelay
=
cfg
->
slavedelay
*
HZ
;
idev
->
pppbind
=
cfg
->
pppbind
;
lp
->
dialtimeout
=
cfg
->
dialtimeout
>=
0
?
cfg
->
dialtimeout
*
HZ
:
-
1
;
lp
->
dialwait
=
cfg
->
dialwait
*
HZ
;
if
(
cfg
->
secure
)
lp
->
flags
|=
ISDN_NET_SECURE
;
else
lp
->
flags
&=
~
ISDN_NET_SECURE
;
if
(
cfg
->
cbhup
)
lp
->
flags
|=
ISDN_NET_CBHUP
;
else
lp
->
flags
&=
~
ISDN_NET_CBHUP
;
switch
(
cfg
->
callback
)
{
case
0
:
lp
->
flags
&=
~
(
ISDN_NET_CALLBACK
|
ISDN_NET_CBOUT
);
break
;
case
1
:
lp
->
flags
|=
ISDN_NET_CALLBACK
;
lp
->
flags
&=
~
ISDN_NET_CBOUT
;
break
;
case
2
:
lp
->
flags
|=
ISDN_NET_CBOUT
;
lp
->
flags
&=
~
ISDN_NET_CALLBACK
;
break
;
}
lp
->
flags
&=
~
ISDN_NET_DIALMODE_MASK
;
/* first all bits off */
if
(
cfg
->
dialmode
&&
!
(
cfg
->
dialmode
&
ISDN_NET_DIALMODE_MASK
))
{
retval
=
-
EINVAL
;
goto
out
;
}
lp
->
flags
|=
cfg
->
dialmode
;
/* turn on selected bits */
if
(
lp
->
flags
&
ISDN_NET_DM_OFF
)
isdn_net_hangup
(
idev
);
if
(
cfg
->
chargehup
)
lp
->
hupflags
|=
ISDN_CHARGEHUP
;
else
lp
->
hupflags
&=
~
ISDN_CHARGEHUP
;
if
(
cfg
->
ihup
)
lp
->
hupflags
|=
ISDN_INHUP
;
else
lp
->
hupflags
&=
~
ISDN_INHUP
;
if
(
cfg
->
chargeint
>
10
)
{
idev
->
chargeint
=
cfg
->
chargeint
*
HZ
;
idev
->
charge_state
=
ST_CHARGE_HAVE_CINT
;
lp
->
hupflags
|=
ISDN_MANCHARGE
;
}
retval
=
0
;
out:
return
retval
;
}
/*
* Perform get-interface-parameters.ioctl
*/
int
isdn_net_getcfg
(
isdn_net_ioctl_cfg
*
cfg
)
{
isdn_net_dev
*
idev
=
isdn_net_findif
(
cfg
->
name
);
isdn_net_local
*
lp
=
&
idev
->
local
;
if
(
!
idev
)
return
-
ENODEV
;
strcpy
(
cfg
->
eaz
,
lp
->
msn
);
cfg
->
exclusive
=
idev
->
exclusive
>=
0
;
if
(
idev
->
pre_device
>=
0
)
{
sprintf
(
cfg
->
drvid
,
"%s,%d"
,
dev
->
drvid
[
idev
->
pre_device
],
idev
->
pre_channel
);
}
else
cfg
->
drvid
[
0
]
=
'\0'
;
cfg
->
onhtime
=
lp
->
onhtime
;
cfg
->
charge
=
idev
->
charge
;
cfg
->
l2_proto
=
lp
->
l2_proto
;
cfg
->
l3_proto
=
lp
->
l3_proto
;
cfg
->
p_encap
=
lp
->
p_encap
;
cfg
->
secure
=
(
lp
->
flags
&
ISDN_NET_SECURE
)
?
1
:
0
;
cfg
->
callback
=
0
;
if
(
lp
->
flags
&
ISDN_NET_CALLBACK
)
cfg
->
callback
=
1
;
if
(
lp
->
flags
&
ISDN_NET_CBOUT
)
cfg
->
callback
=
2
;
cfg
->
cbhup
=
(
lp
->
flags
&
ISDN_NET_CBHUP
)
?
1
:
0
;
cfg
->
dialmode
=
lp
->
flags
&
ISDN_NET_DIALMODE_MASK
;
cfg
->
chargehup
=
(
lp
->
hupflags
&
ISDN_CHARGEHUP
)
?
1
:
0
;
cfg
->
ihup
=
(
lp
->
hupflags
&
ISDN_INHUP
)
?
1
:
0
;
cfg
->
cbdelay
=
lp
->
cbdelay
*
5
/
HZ
;
cfg
->
dialmax
=
lp
->
dialmax
;
cfg
->
triggercps
=
lp
->
triggercps
;
cfg
->
slavedelay
=
lp
->
slavedelay
/
HZ
;
cfg
->
chargeint
=
(
lp
->
hupflags
&
ISDN_CHARGEHUP
)
?
(
idev
->
chargeint
/
HZ
)
:
0
;
cfg
->
pppbind
=
idev
->
pppbind
;
cfg
->
dialtimeout
=
lp
->
dialtimeout
>=
0
?
lp
->
dialtimeout
/
HZ
:
-
1
;
cfg
->
dialwait
=
lp
->
dialwait
/
HZ
;
if
(
lp
->
slave
)
strcpy
(
cfg
->
slave
,
((
isdn_net_local
*
)
lp
->
slave
->
priv
)
->
netdev
->
name
);
else
cfg
->
slave
[
0
]
=
'\0'
;
if
(
lp
->
master
)
strcpy
(
cfg
->
master
,
((
isdn_net_local
*
)
lp
->
master
->
priv
)
->
netdev
->
name
);
else
cfg
->
master
[
0
]
=
'\0'
;
list_del
(
&
mlp
->
online
);
list_add_tail
(
&
mlp
->
online
,
&
idev
->
online
);
}
return
0
;
}
/*
* Add a phone-number to an interface.
*/
int
isdn_net_a
ddphone
(
isdn_net_ioctl_phone
*
phone
)
isdn_net_a
utodial
(
struct
sk_buff
*
skb
,
struct
net_device
*
ndev
)
{
isdn_net_dev
*
p
=
isdn_net_findif
(
phone
->
name
);
unsigned
long
flags
;
struct
isdn_net_phone
*
n
;
isdn_net_local
*
mlp
=
ndev
->
priv
;
isdn_net_dev
*
idev
=
list_entry
(
mlp
->
slaves
.
next
,
isdn_net_dev
,
slaves
);
/* are we dialing already? */
if
(
isdn_net_bound
(
idev
))
goto
stop_queue
;
if
(
!
p
)
return
-
ENODEV
;
if
(
ISDN_NET_DIALMODE
(
*
mlp
)
!=
ISDN_NET_DM_AUTO
)
goto
discard
;
if
(
isdn_net_dial
(
idev
)
<
0
)
goto
discard
;
/* Log packet, which triggered dialing */
if
(
dev
->
net_verbose
)
isdn_net_log_skb
(
skb
,
idev
);
n
=
kmalloc
(
sizeof
(
*
n
),
GFP_KERNEL
);
if
(
!
n
)
return
-
ENOMEM
;
stop_queue:
netif_stop_queue
(
ndev
);
return
1
;
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
);
discard:
isdn_net_unreachable
(
ndev
,
skb
,
"dial rejected"
);
dev_kfree_skb
(
skb
);
return
0
;
}
/*
* Copy a string of all phone-numbers of an interface to user space.
* This might sleep and must be called with the isdn semaphore down.
* Got a packet from ISDN-Channel.
*/
int
isdn_net_
getphones
(
isdn_net_ioctl_phone
*
phone
,
char
*
phones
)
static
void
isdn_net_
receive
(
isdn_net_dev
*
idev
,
struct
sk_buff
*
skb
)
{
isdn_net_dev
*
p
=
isdn_net_findif
(
phone
->
name
);
unsigned
long
flags
;
int
inout
=
phone
->
outgoing
&
1
;
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
)
{
strcpy
(
&
buf
[
count
],
n
->
num
);
count
+=
strlen
(
n
->
num
);
buf
[
count
++
]
=
' '
;
if
(
count
>
PAGE_SIZE
-
ISDN_MSNLEN
-
1
)
break
;
}
spin_unlock_irqrestore
(
&
p
->
local
.
lock
,
flags
);
if
(
!
count
)
count
++
;
isdn_net_local
*
mlp
=
idev
->
mlp
;
buf
[
count
-
1
]
=
0
;
idev
->
transcount
+=
skb
->
len
;
if
(
copy_to_user
(
phones
,
buf
,
count
))
count
=
-
EFAULT
;
mlp
->
stats
.
rx_packets
++
;
mlp
->
stats
.
rx_bytes
+=
skb
->
len
;
skb
->
dev
=
&
mlp
->
dev
;
skb
->
pkt_type
=
PACKET_HOST
;
skb
->
mac
.
raw
=
skb
->
data
;
isdn_dumppkt
(
"R:"
,
skb
->
data
,
skb
->
len
,
40
);
free_page
((
unsigned
long
)
buf
);
return
count
;
mlp
->
ops
->
receive
(
mlp
,
idev
,
skb
);
}
/*
* Copy a string containing the peer's phone number of a connected interface
* to user space.
* A packet arrived via ISDN. Search interface-chain for a corresponding
* interface. If found, deliver packet to receiver-function and return 1,
* else return 0.
*/
int
isdn_net_
getpeer
(
isdn_net_ioctl_phone
*
phone
,
isdn_net_ioctl_phone
*
peer
)
isdn_net_
rcv_skb
(
int
idx
,
struct
sk_buff
*
skb
)
{
isdn_net_dev
*
p
=
isdn_net_findif
(
phone
->
name
);
int
idx
;
isdn_net_dev
*
idev
=
isdn_slot_idev
(
idx
);
if
(
!
p
)
return
-
ENODEV
;
/*
* Theoretical race: while this executes, the remote number might
* become invalid (hang up) or change (new connection), resulting
* in (partially) wrong number copied to user. This race
* currently ignored.
*/
idx
=
p
->
isdn_slot
;
if
(
idx
<
0
)
return
-
ENOTCONN
;
/* for pre-bound channels, we need this extra check */
if
(
strncmp
(
isdn_slot_num
(
idx
),
"???"
,
3
)
==
0
)
return
-
ENOTCONN
;
strncpy
(
phone
->
phone
,
isdn_slot_num
(
idx
),
ISDN_MSNLEN
);
phone
->
outgoing
=
USG_OUTGOING
(
isdn_slot_usage
(
idx
));
if
(
copy_to_user
(
peer
,
phone
,
sizeof
(
*
peer
))
)
return
-
EFAULT
;
if
(
!
idev
)
{
HERE
;
return
0
;
}
/*
* Delete a phone-number from an interface.
*/
int
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
;
unsigned
long
flags
;
int
retval
;
if
(
!
p
)
return
-
ENODEV
;
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
);
retval
=
0
;
break
;
}
}
spin_unlock_irqrestore
(
&
p
->
local
.
lock
,
flags
);
return
retval
;
if
(
!
isdn_net_online
(
idev
))
return
0
;
isdn_net_receive
(
idev
,
skb
);
return
0
;
}
/*
* Delete all phone-numbers of an interface.
* 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.
*/
static
int
isdn_net_
rmallphone
(
isdn_net_dev
*
p
)
int
isdn_net_
find_icall
(
int
di
,
int
ch
,
int
idx
,
setup_parm
*
setu
p
)
{
char
*
eaz
;
unsigned
char
si1
,
si2
;
int
match_more
=
0
;
int
retval
;
struct
list_head
*
l
;
struct
isdn_net_phone
*
n
;
unsigned
long
flags
;
int
i
;
ulong
flags
;
char
nr
[
32
];
char
*
my_eaz
;
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
);
list_del
(
&
n
->
list
);
kfree
(
n
);
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
;
}
spin_lock_irqsave
(
&
p
->
local
.
lock
,
flags
);
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
;
}
}
/*
* Force a hangup of a network-interface.
*/
int
isdn_net_force_hangup
(
char
*
name
)
{
isdn_net_dev
*
idev
=
isdn_net_findif
(
name
);
struct
net_device
*
q
;
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
;
if
(
!
idev
)
return
-
ENODEV
;
/* 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
);
if
(
idev
->
isdn_slot
<
0
)
return
-
ENOTCONN
;
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 */
}
q
=
idev
->
local
.
slave
;
/* If this interface has slaves, do a hangup for them also. */
while
(
q
)
{
isdn_net_hangup
(((
isdn_net_local
*
)
q
->
priv
)
->
netdev
);
q
=
(((
isdn_net_local
*
)
q
->
priv
)
->
slave
);
switch
(
isdn_msncmp
(
eaz
,
my_eaz
))
{
case
1
:
continue
;
case
2
:
match_more
=
1
;
continue
;
}
isdn_net_hangup
(
idev
);
return
0
;
}
/*
* Helper-function for isdn_net_rm: Do the real work.
*/
static
int
isdn_net_realrm
(
isdn_net_dev
*
p
)
{
unsigned
long
flags
;
if
(
isdn_net_bound
(
idev
))
continue
;
save_flags
(
flags
);
cli
();
if
(
isdn_net_device_started
(
p
))
{
restore_flags
(
flags
);
return
-
EBUSY
;
}
isdn_net_set_encap
(
p
,
-
1
);
/* Free all phone-entries */
isdn_net_rmallphone
(
p
);
/* If interface is bound exclusive, free channel-usage */
if
(
p
->
exclusive
>=
0
)
isdn_unexclusive_channel
(
p
->
pre_device
,
p
->
pre_channel
);
if
(
p
->
local
.
master
)
{
/* It's a slave-device, so update master's slave-pointer if necessary */
if
(((
isdn_net_local
*
)
(
p
->
local
.
master
->
priv
))
->
slave
==
&
p
->
dev
)
((
isdn_net_local
*
)
(
p
->
local
.
master
->
priv
))
->
slave
=
p
->
local
.
slave
;
}
else
{
/* Unregister only if it's a master-device */
unregister_netdev
(
&
p
->
dev
);
}
/* Unlink device from chain */
list_del
(
&
p
->
global_list
);
if
(
p
->
local
.
slave
)
{
/* If this interface has a slave, remove it also */
char
*
slavename
=
((
isdn_net_local
*
)
(
p
->
local
.
slave
->
priv
))
->
netdev
->
name
;
struct
list_head
*
l
;
if
(
!
USG_NONE
(
isdn_slot_usage
(
idx
)))
continue
;
list_for_each
(
l
,
&
isdn_net_devs
)
{
isdn_net_dev
*
n
=
list_entry
(
l
,
isdn_net_dev
,
global_list
);
if
(
!
strcmp
(
n
->
name
,
slavename
))
{
isdn_net_realrm
(
n
);
break
;
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
;
}
}
restore_flags
(
flags
)
;
kfree
(
p
);
return
0
;
}
continue
;
}
found:
dbg_net_icall
(
"n_fi: match3
\n
"
)
;
/* matching interface found */
/*
* Remove a single network-interface.
/*
* 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.
*/
int
isdn_net_rm
(
char
*
name
)
{
struct
list_head
*
l
;
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
);
/* Search name in netdev-chain */
list_for_each
(
l
,
&
isdn_net_devs
)
{
isdn_net_dev
*
p
=
list_entry
(
l
,
isdn_net_dev
,
global_list
);
if
(
!
strcmp
(
p
->
name
,
name
))
return
isdn_net_realrm
(
p
);
isdn_net_accept
(
idev
,
idx
,
nr
);
restore_flags
(
flags
);
return
1
;
}
return
-
ENODEV
;
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
;
}
/*
* Remove all network-interfaces
* This is called from certain upper protocol layers (multilink ppp
* and x25iface encapsulation module) that want to initiate dialing
* themselves.
*/
int
isdn_net_
rmall
(
void
)
isdn_net_
dial_req
(
isdn_net_dev
*
idev
)
{
unsigned
long
flags
;
int
ret
;
/* Walk through netdev-chain */
save_flags
(
flags
);
cli
();
while
(
!
list_empty
(
&
isdn_net_devs
))
{
isdn_net_dev
*
p
=
list_entry
(
isdn_net_devs
.
next
,
isdn_net_dev
,
global_list
);
isdn_net_local
*
mlp
=
idev
->
mlp
;
/* is there a better error code? */
if
(
ISDN_NET_DIALMODE
(
*
mlp
)
!=
ISDN_NET_DM_AUTO
)
return
-
EBUSY
;
/* Remove master-devices only, slaves get removed with their master */
if
(
!
p
->
local
.
master
)
{
if
((
ret
=
isdn_net_realrm
(
p
)))
{
restore_flags
(
flags
);
return
ret
;
}
}
}
restore_flags
(
flags
);
return
0
;
return
isdn_net_dial
(
idev
);
}
// ISDN_NET_ENCAP_IPTYP
...
...
@@ -2212,16 +610,17 @@ isdn_iptyp_header(struct sk_buff *skb, struct net_device *dev,
}
static
void
isdn_iptyp_receive
(
isdn_net_
dev
*
p
,
isdn_net_local
*
olp
,
isdn_iptyp_receive
(
isdn_net_
local
*
lp
,
isdn_net_dev
*
idev
,
struct
sk_buff
*
skb
)
{
i
sdn_net_reset_huptimer
(
p
,
olp
->
netdev
)
;
i
dev
->
huptimer
=
0
;
get_u16
(
skb
->
data
,
&
skb
->
protocol
);
skb_pull
(
skb
,
2
);
netif_rx
(
skb
);
}
static
struct
isdn_netif_ops
iptyp_ops
=
{
.
hard_start_xmit
=
isdn_net_start_xmit
,
.
hard_header
=
isdn_iptyp_header
,
.
flags
=
IFF_NOARP
|
IFF_POINTOPOINT
,
.
type
=
ARPHRD_PPP
,
...
...
@@ -2243,16 +642,17 @@ isdn_uihdlc_header(struct sk_buff *skb, struct net_device *dev,
}
static
void
isdn_uihdlc_receive
(
isdn_net_
dev
*
p
,
isdn_net_local
*
olp
,
isdn_uihdlc_receive
(
isdn_net_
local
*
lp
,
isdn_net_dev
*
idev
,
struct
sk_buff
*
skb
)
{
i
sdn_net_reset_huptimer
(
p
,
olp
->
netdev
)
;
i
dev
->
huptimer
=
0
;
skb_pull
(
skb
,
2
);
skb
->
protocol
=
htons
(
ETH_P_IP
);
netif_rx
(
skb
);
}
static
struct
isdn_netif_ops
uihdlc_ops
=
{
.
hard_start_xmit
=
isdn_net_start_xmit
,
.
hard_header
=
isdn_uihdlc_header
,
.
flags
=
IFF_NOARP
|
IFF_POINTOPOINT
,
.
type
=
ARPHRD_HDLC
,
...
...
@@ -2265,15 +665,16 @@ static struct isdn_netif_ops uihdlc_ops = {
// ======================================================================
static
void
isdn_rawip_receive
(
isdn_net_
dev
*
p
,
isdn_net_local
*
olp
,
isdn_rawip_receive
(
isdn_net_
local
*
lp
,
isdn_net_dev
*
idev
,
struct
sk_buff
*
skb
)
{
i
sdn_net_reset_huptimer
(
p
,
olp
->
netdev
)
;
i
dev
->
huptimer
=
0
;
skb
->
protocol
=
htons
(
ETH_P_IP
);
netif_rx
(
skb
);
}
static
struct
isdn_netif_ops
rawip_ops
=
{
.
hard_start_xmit
=
isdn_net_start_xmit
,
.
flags
=
IFF_NOARP
|
IFF_POINTOPOINT
,
.
type
=
ARPHRD_PPP
,
.
receive
=
isdn_rawip_receive
,
...
...
@@ -2283,73 +684,19 @@ static struct isdn_netif_ops rawip_ops = {
// Ethernet over ISDN
// ======================================================================
/* This is simply a copy from std. eth.c EXCEPT we pull ETH_HLEN
* instead of dev->hard_header_len off. This is done because the
* lowlevel-driver has already pulled off its stuff when we get
* here and this routine only gets called with p_encap == ETHER.
* Determine the packet's protocol ID. The rule here is that we
* assume 802.3 if the type field is short enough to be a length.
* This is normal practice and works for any 'now in use' protocol.
* FIXME
*/
static
unsigned
short
isdn_eth_type_trans
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
{
struct
ethhdr
*
eth
;
unsigned
char
*
rawp
;
skb
->
mac
.
raw
=
skb
->
data
;
skb_pull
(
skb
,
ETH_HLEN
);
eth
=
skb
->
mac
.
ethernet
;
if
(
*
eth
->
h_dest
&
1
)
{
if
(
memcmp
(
eth
->
h_dest
,
dev
->
broadcast
,
ETH_ALEN
)
==
0
)
skb
->
pkt_type
=
PACKET_BROADCAST
;
else
skb
->
pkt_type
=
PACKET_MULTICAST
;
}
/*
* This ALLMULTI check should be redundant by 1.4
* so don't forget to remove it.
*/
else
if
(
dev
->
flags
&
(
IFF_PROMISC
/*| IFF_ALLMULTI*/
))
{
if
(
memcmp
(
eth
->
h_dest
,
dev
->
dev_addr
,
ETH_ALEN
))
skb
->
pkt_type
=
PACKET_OTHERHOST
;
}
if
(
ntohs
(
eth
->
h_proto
)
>=
1536
)
return
eth
->
h_proto
;
rawp
=
skb
->
data
;
/*
* This is a magic hack to spot IPX packets. Older Novell breaks
* the protocol design and runs IPX over 802.3 without an 802.2 LLC
* layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
* won't work for fault tolerant netware but does for the rest.
*/
if
(
*
(
unsigned
short
*
)
rawp
==
0xFFFF
)
return
htons
(
ETH_P_802_3
);
/*
* Real 802.2 LLC
*/
return
htons
(
ETH_P_802_2
);
}
static
void
isdn_ether_receive
(
isdn_net_
dev
*
p
,
isdn_net_local
*
olp
,
isdn_ether_receive
(
isdn_net_
local
*
lp
,
isdn_net_dev
*
idev
,
struct
sk_buff
*
skb
)
{
i
sdn_net_reset_huptimer
(
p
,
olp
->
netdev
)
;
skb
->
protocol
=
isdn_
eth_type_trans
(
skb
,
skb
->
dev
);
i
dev
->
huptimer
=
0
;
skb
->
protocol
=
eth_type_trans
(
skb
,
skb
->
dev
);
netif_rx
(
skb
);
}
static
int
isdn_ether_open
(
isdn_net_local
*
lp
)
{
struct
net_device
*
dev
=
&
lp
->
netdev
->
dev
;
struct
net_device
*
dev
=
&
lp
->
dev
;
struct
in_device
*
in_dev
;
int
i
;
...
...
@@ -2369,7 +716,7 @@ isdn_ether_open(isdn_net_local *lp)
static
int
isdn_ether_init
(
isdn_net_local
*
lp
)
{
struct
net_device
*
dev
=
&
lp
->
netdev
->
dev
;
struct
net_device
*
dev
=
&
lp
->
dev
;
ether_setup
(
dev
);
dev
->
tx_queue_len
=
10
;
...
...
@@ -2379,6 +726,7 @@ isdn_ether_init(isdn_net_local *lp)
}
static
struct
isdn_netif_ops
ether_ops
=
{
.
hard_start_xmit
=
isdn_net_start_xmit
,
.
hard_header
=
eth_header
,
.
receive
=
isdn_ether_receive
,
.
init
=
isdn_ether_init
,
...
...
@@ -2388,7 +736,7 @@ static struct isdn_netif_ops ether_ops = {
// ======================================================================
void
isdn_net_init
_module
(
void
)
isdn_net_init
(
void
)
{
register_isdn_netif
(
ISDN_NET_ENCAP_ETHER
,
&
ether_ops
);
register_isdn_netif
(
ISDN_NET_ENCAP_RAWIP
,
&
rawip_ops
);
...
...
@@ -2402,4 +750,7 @@ isdn_net_init_module(void)
#ifdef CONFIG_ISDN_PPP
register_isdn_netif
(
ISDN_NET_ENCAP_SYNCPPP
,
&
isdn_ppp_ops
);
#endif
isdn_net_lib_init
();
}
drivers/isdn/i4l/isdn_net.h
View file @
994b6e06
...
...
@@ -32,46 +32,49 @@
#define CISCO_SLARP_REPLY 1
#define CISCO_SLARP_KEEPALIVE 2
extern
void
isdn_net_init_module
(
void
);
extern
void
isdn_net_init
(
void
);
extern
void
isdn_net_exit
(
void
);
extern
void
isdn_net_lib_init
(
void
);
extern
void
isdn_net_lib_exit
(
void
);
extern
void
isdn_net_hangup_all
(
void
);
extern
int
isdn_net_ioctl
(
struct
inode
*
,
struct
file
*
,
uint
,
ulong
);
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
);
extern
int
isdn_net_new
(
char
*
,
struct
net_device
*
);
extern
int
isdn_net_newslave
(
char
*
);
extern
int
isdn_net_rm
(
char
*
);
extern
int
isdn_net_rmall
(
void
);
extern
int
isdn_net_stat_callback
(
int
,
isdn_ctrl
*
);
extern
int
isdn_net_setcfg
(
isdn_net_ioctl_cfg
*
);
extern
int
isdn_net_getcfg
(
isdn_net_ioctl_cfg
*
);
extern
int
isdn_net_addphone
(
isdn_net_ioctl_phone
*
);
extern
int
isdn_net_getphones
(
isdn_net_ioctl_phone
*
,
char
*
);
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_dev
*
);
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
*
);
extern
int
isdn_net_hangup
(
isdn_net_dev
*
);
extern
int
isdn_net_rcv_skb
(
int
,
struct
sk_buff
*
);
extern
int
isdn_net_dial_req
(
isdn_net_
local
*
);
extern
void
isdn_net_writebuf_skb
(
isdn_net_
local
*
lp
,
struct
sk_buff
*
skb
);
extern
void
isdn_net_write_super
(
isdn_net_
local
*
lp
,
struct
sk_buff
*
skb
);
extern
int
isdn_net_online
(
isdn_net_dev
*
idev
);
extern
int
isdn_net_dial_req
(
isdn_net_
dev
*
);
extern
void
isdn_net_writebuf_skb
(
isdn_net_
dev
*
,
struct
sk_buff
*
skb
);
extern
void
isdn_net_write_super
(
isdn_net_
dev
*
,
struct
sk_buff
*
skb
);
extern
int
isdn_net_online
(
isdn_net_dev
*
);
static
inline
void
isdn_net_reset_huptimer
(
isdn_net_dev
*
idev
,
isdn_net_dev
*
idev2
)
{
idev
->
huptimer
=
0
;
idev2
->
huptimer
=
0
;
}
enum
{
ST_CHARGE_NULL
,
ST_CHARGE_GOT_CINF
,
/* got a first charge info */
ST_CHARGE_HAVE_CINT
,
/* got a second chare info and thus the timing */
};
#define ISDN_NET_MAX_QUEUE_LENGTH 2
/*
* is this particular channel busy?
*/
static
__inline__
int
isdn_net_lp_busy
(
isdn_net_local
*
lp
)
static
inline
int
isdn_net_dev_busy
(
isdn_net_dev
*
idev
)
{
if
(
atomic_read
(
&
lp
->
frame_cnt
)
<
ISDN_NET_MAX_QUEUE_LENGTH
)
if
(
atomic_read
(
&
idev
->
frame_cnt
)
<
ISDN_NET_MAX_QUEUE_LENGTH
)
return
0
;
else
return
1
;
...
...
@@ -81,86 +84,69 @@ static __inline__ int isdn_net_lp_busy(isdn_net_local *lp)
* For the given net device, this will get a non-busy channel out of the
* corresponding bundle. The returned channel is locked.
*/
static
__inline__
isdn_net_local
*
isdn_net_get_locked_lp
(
isdn_net_dev
*
nd
)
static
inline
isdn_net_dev
*
isdn_net_get_locked_dev
(
isdn_net_local
*
mlp
)
{
unsigned
long
flags
;
isdn_net_
local
*
lp
;
spin_lock_irqsave
(
&
nd
->
queu
e_lock
,
flags
);
lp
=
nd
->
queue
;
/* get lp on top of queue */
spin_lock_bh
(
&
nd
->
queue
->
xmit_lock
);
while
(
isdn_net_lp_busy
(
nd
->
queue
))
{
spin_unlock_bh
(
&
nd
->
queue
->
xmit_lock
);
nd
->
queue
=
nd
->
queue
->
next
;
if
(
nd
->
queue
==
lp
)
{
/* not found -- should never happen */
l
p
=
NULL
;
goto
errout
;
isdn_net_
dev
*
idev
;
spin_lock_irqsave
(
&
mlp
->
onlin
e_lock
,
flags
);
list_for_each_entry
(
idev
,
&
mlp
->
online
,
online
)
{
spin_lock_bh
(
&
idev
->
xmit_lock
);
if
(
!
isdn_net_dev_busy
(
idev
))
{
/* point the head to next online channel */
list_del
(
&
mlp
->
online
);
l
ist_add
(
&
mlp
->
online
,
&
idev
->
online
)
;
goto
found
;
}
spin_
lock_bh
(
&
nd
->
queue
->
xmit_lock
);
spin_
unlock_bh
(
&
idev
->
xmit_lock
);
}
lp
=
nd
->
queue
;
nd
->
queue
=
nd
->
queue
->
next
;
errout
:
spin_unlock_irqrestore
(
&
nd
->
queu
e_lock
,
flags
);
return
lp
;
idev
=
NULL
;
found
:
spin_unlock_irqrestore
(
&
mlp
->
onlin
e_lock
,
flags
);
return
idev
;
}
/*
* add a channel to a bundle
*/
static
__inline__
void
isdn_net_add_to_bundle
(
isdn_net_dev
*
nd
,
isdn_net_local
*
nlp
)
static
inline
void
isdn_net_add_to_bundle
(
isdn_net_local
*
mlp
,
isdn_net_dev
*
idev
)
{
isdn_net_local
*
lp
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
nd
->
queue_lock
,
flags
);
lp
=
nd
->
queue
;
nlp
->
last
=
lp
->
last
;
lp
->
last
->
next
=
nlp
;
lp
->
last
=
nlp
;
nlp
->
next
=
lp
;
nd
->
queue
=
nlp
;
spin_unlock_irqrestore
(
&
nd
->
queue_lock
,
flags
);
spin_lock_irqsave
(
&
mlp
->
online_lock
,
flags
);
list_add
(
&
idev
->
online
,
&
mlp
->
online
);
spin_unlock_irqrestore
(
&
mlp
->
online_lock
,
flags
);
}
/*
* remove a channel from the bundle it belongs to
*/
static
__inline__
void
isdn_net_rm_from_bundle
(
isdn_net_local
*
lp
)
static
inline
void
isdn_net_rm_from_bundle
(
isdn_net_dev
*
idev
)
{
isdn_net_local
*
m
aster_lp
=
lp
;
isdn_net_local
*
m
lp
=
idev
->
m
lp
;
unsigned
long
flags
;
if
(
lp
->
master
)
master_lp
=
(
isdn_net_local
*
)
lp
->
master
->
priv
;
spin_lock_irqsave
(
&
master_lp
->
netdev
->
queue_lock
,
flags
);
lp
->
last
->
next
=
lp
->
next
;
lp
->
next
->
last
=
lp
->
last
;
if
(
master_lp
->
netdev
->
queue
==
lp
)
{
master_lp
->
netdev
->
queue
=
lp
->
next
;
if
(
lp
->
next
==
lp
)
{
/* last in queue */
master_lp
->
netdev
->
queue
=
&
master_lp
->
netdev
->
local
;
}
}
lp
->
next
=
lp
->
last
=
lp
;
/* (re)set own pointers */
spin_unlock_irqrestore
(
&
master_lp
->
netdev
->
queue_lock
,
flags
);
spin_lock_irqsave
(
&
mlp
->
online_lock
,
flags
);
// list_del(&idev->online); FIXME
spin_unlock_irqrestore
(
&
mlp
->
online_lock
,
flags
);
}
/*
* wake up the network -> net_device queue.
* For slaves, wake the corresponding master interface.
*/
static
inline
void
isdn_net_device_wake_queue
(
isdn_net_local
*
lp
)
static
inline
void
isdn_net_dev_wake_queue
(
isdn_net_dev
*
idev
)
{
if
(
lp
->
master
)
netif_wake_queue
(
lp
->
master
);
else
netif_wake_queue
(
&
lp
->
netdev
->
dev
);
netif_wake_queue
(
&
idev
->
mlp
->
dev
);
}
static
inline
int
isdn_net_bound
(
isdn_net_dev
*
idev
)
static
inline
int
isdn_net_bound
(
isdn_net_dev
*
idev
)
{
return
idev
->
isdn_slot
>=
0
;
}
...
...
drivers/isdn/i4l/isdn_net_lib.c
0 → 100644
View file @
994b6e06
/*
* Linux ISDN subsystem, Network interface configuration
*
* Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de)
* 1995,96 by Thinking Objects Software GmbH Wuerzburg
* 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
* 1999-2002 by Kai Germaschewski <kai@germaschewski.name>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/socket.h>
#include <linux/capability.h>
#include <linux/rtnetlink.h>
#include "isdn_common.h"
#include "isdn_net.h"
#include "isdn_ppp.h"
#include "isdn_fsm.h"
#define ISDN_NET_TX_TIMEOUT (20*HZ)
/* All of this configuration code is globally serialized */
static
DECLARE_MUTEX
(
sem
);
LIST_HEAD
(
isdn_net_devs
);
/* Linked list of isdn_net_dev's */
// FIXME static
int
isdn_net_handle_event
(
isdn_net_dev
*
idev
,
int
pr
,
void
*
arg
);
/* FIXME */
static
void
isdn_net_tasklet
(
unsigned
long
data
);
static
void
isdn_net_dial_timer
(
unsigned
long
data
);
static
int
isdn_init_netif
(
struct
net_device
*
ndev
);
static
void
isdn_net_dev_debug
(
struct
fsm_inst
*
fi
,
char
*
fmt
,
...);
static
struct
fsm
isdn_net_fsm
;
enum
{
ST_NULL
,
ST_OUT_WAIT_DCONN
,
ST_OUT_WAIT_BCONN
,
ST_IN_WAIT_DCONN
,
ST_IN_WAIT_BCONN
,
ST_ACTIVE
,
ST_WAIT_BEFORE_CB
,
ST_OUT_DIAL_WAIT
,
};
static
char
*
isdn_net_st_str
[]
=
{
"ST_NULL"
,
"ST_OUT_WAIT_DCONN"
,
"ST_OUT_WAIT_BCONN"
,
"ST_IN_WAIT_DCONN"
,
"ST_IN_WAIT_BCONN"
,
"ST_ACTIVE"
,
"ST_WAIT_BEFORE_CB"
,
"ST_OUT_DIAL_WAIT"
,
};
enum
{
EV_TIMER_INCOMING
,
EV_TIMER_DIAL
,
EV_TIMER_DIAL_WAIT
,
EV_TIMER_CB_OUT
,
EV_TIMER_CB_IN
,
EV_TIMER_HUP
,
EV_STAT_DCONN
,
EV_STAT_BCONN
,
EV_STAT_DHUP
,
EV_STAT_BHUP
,
EV_STAT_CINF
,
EV_STAT_BSENT
,
};
static
char
*
isdn_net_ev_str
[]
=
{
"EV_NET_TIMER_INCOMING"
,
"EV_NET_TIMER_DIAL"
,
"EV_NET_TIMER_DIAL_WAIT"
,
"EV_NET_TIMER_CB_OUT"
,
"EV_NET_TIMER_CB_IN"
,
"EV_NET_TIMER_HUP"
,
"EV_STAT_DCONN"
,
"EV_STAT_BCONN"
,
"EV_STAT_DHUP"
,
"EV_STAT_BHUP"
,
"EV_STAT_CINF"
,
"EV_STAT_BSENT"
,
};
/* ====================================================================== */
/* Registration of ISDN network interface types */
/* ====================================================================== */
static
struct
isdn_netif_ops
*
isdn_netif_ops
[
ISDN_NET_ENCAP_NR
];
int
register_isdn_netif
(
int
encap
,
struct
isdn_netif_ops
*
ops
)
{
if
(
encap
<
0
||
encap
>=
ISDN_NET_ENCAP_NR
)
return
-
EINVAL
;
if
(
isdn_netif_ops
[
encap
])
return
-
EBUSY
;
isdn_netif_ops
[
encap
]
=
ops
;
return
0
;
}
/* ====================================================================== */
/* Helpers */
/* ====================================================================== */
/* Search list of net-interfaces for an interface with given name. */
static
isdn_net_dev
*
isdn_net_findif
(
char
*
name
)
{
isdn_net_dev
*
idev
;
list_for_each_entry
(
idev
,
&
isdn_net_devs
,
global_list
)
{
if
(
!
strcmp
(
idev
->
name
,
name
))
return
idev
;
}
return
NULL
;
}
/* Set up a certain encapsulation */
static
int
isdn_net_set_encap
(
isdn_net_local
*
lp
,
int
encap
)
{
int
retval
=
0
;
if
(
lp
->
p_encap
==
encap
){
/* nothing to do */
retval
=
0
;
goto
out
;
}
if
(
netif_running
(
&
lp
->
dev
))
{
retval
=
-
EBUSY
;
goto
out
;
}
if
(
lp
->
ops
&&
lp
->
ops
->
cleanup
)
lp
->
ops
->
cleanup
(
lp
);
if
(
encap
<
0
||
encap
>=
ISDN_NET_ENCAP_NR
)
{
lp
->
p_encap
=
-
1
;
lp
->
ops
=
NULL
;
retval
=
-
EINVAL
;
goto
out
;
}
lp
->
p_encap
=
encap
;
lp
->
ops
=
isdn_netif_ops
[
encap
];
lp
->
dev
.
hard_start_xmit
=
lp
->
ops
->
hard_start_xmit
;
lp
->
dev
.
hard_header
=
lp
->
ops
->
hard_header
;
lp
->
dev
.
do_ioctl
=
lp
->
ops
->
do_ioctl
;
lp
->
dev
.
flags
=
lp
->
ops
->
flags
;
lp
->
dev
.
type
=
lp
->
ops
->
type
;
lp
->
dev
.
addr_len
=
lp
->
ops
->
addr_len
;
if
(
lp
->
ops
->
init
)
retval
=
lp
->
ops
->
init
(
lp
);
if
(
retval
!=
0
)
{
lp
->
p_encap
=
-
1
;
lp
->
ops
=
NULL
;
}
out:
return
retval
;
}
static
int
isdn_net_bind
(
isdn_net_dev
*
idev
,
isdn_net_ioctl_cfg
*
cfg
)
{
isdn_net_local
*
mlp
=
idev
->
mlp
;
int
i
,
retval
;
int
drvidx
=
-
1
;
int
chidx
=
-
1
;
char
drvid
[
25
];
strncpy
(
drvid
,
cfg
->
drvid
,
24
);
drvid
[
24
]
=
0
;
if
(
cfg
->
exclusive
&&
!
strlen
(
drvid
))
{
/* If we want to bind exclusively, need to specify drv/chan */
retval
=
-
ENODEV
;
goto
out
;
}
if
(
strlen
(
drvid
))
{
/* A bind has been requested ... */
char
*
c
=
strchr
(
drvid
,
','
);
if
(
!
c
)
{
retval
=
-
ENODEV
;
goto
out
;
}
/* The channel-number is appended to the driver-Id with a comma */
*
c
=
0
;
chidx
=
simple_strtol
(
c
+
1
,
NULL
,
10
);
for
(
i
=
0
;
i
<
ISDN_MAX_DRIVERS
;
i
++
)
{
/* Lookup driver-Id in array */
if
(
!
strcmp
(
dev
->
drvid
[
i
],
drvid
))
{
drvidx
=
i
;
break
;
}
}
if
(
drvidx
==
-
1
||
chidx
==
-
1
)
{
/* Either driver-Id or channel-number invalid */
retval
=
-
ENODEV
;
goto
out
;
}
}
if
(
cfg
->
exclusive
==
(
idev
->
exclusive
>=
0
)
&&
drvidx
==
idev
->
pre_device
&&
chidx
==
idev
->
pre_channel
)
{
/* no change */
retval
=
0
;
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
);
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
);
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
;
retval
=
0
;
out:
return
retval
;
}
/*
* Delete all phone-numbers of an interface.
*/
static
void
isdn_net_rmallphone
(
isdn_net_dev
*
idev
)
{
isdn_net_local
*
mlp
=
idev
->
mlp
;
struct
isdn_net_phone
*
n
;
int
i
;
for
(
i
=
0
;
i
<
2
;
i
++
)
{
while
(
!
list_empty
(
&
mlp
->
phone
[
i
]))
{
n
=
list_entry
(
mlp
->
phone
[
i
].
next
,
struct
isdn_net_phone
,
list
);
list_del
(
&
n
->
list
);
kfree
(
n
);
}
}
}
/* ====================================================================== */
/* /dev/isdnctrl net ioctl interface */
/* ====================================================================== */
/*
* Allocate a new network-interface and initialize its data structures
*/
static
int
isdn_net_addif
(
char
*
name
,
isdn_net_local
*
mlp
)
{
int
retval
;
struct
net_device
*
dev
=
NULL
;
isdn_net_dev
*
idev
;
/* Avoid creating an existing interface */
if
(
isdn_net_findif
(
name
))
return
-
EEXIST
;
idev
=
kmalloc
(
sizeof
(
*
idev
),
GFP_KERNEL
);
if
(
!
idev
)
return
-
ENOMEM
;
memset
(
idev
,
0
,
sizeof
(
*
idev
));
strcpy
(
idev
->
name
,
name
);
tasklet_init
(
&
idev
->
tlet
,
isdn_net_tasklet
,
(
unsigned
long
)
idev
);
spin_lock_init
(
&
idev
->
xmit_lock
);
skb_queue_head_init
(
&
idev
->
super_tx_queue
);
idev
->
isdn_slot
=
-
1
;
idev
->
pre_device
=
-
1
;
idev
->
pre_channel
=
-
1
;
idev
->
exclusive
=
-
1
;
idev
->
ppp_slot
=
-
1
;
idev
->
pppbind
=
-
1
;
init_timer
(
&
idev
->
dial_timer
);
idev
->
dial_timer
.
data
=
(
unsigned
long
)
idev
;
idev
->
dial_timer
.
function
=
isdn_net_dial_timer
;
idev
->
fi
.
fsm
=
&
isdn_net_fsm
;
idev
->
fi
.
state
=
ST_NULL
;
idev
->
fi
.
debug
=
1
;
idev
->
fi
.
userdata
=
idev
;
idev
->
fi
.
printdebug
=
isdn_net_dev_debug
;
if
(
!
mlp
)
{
/* Device shall be a master */
mlp
=
kmalloc
(
sizeof
(
*
mlp
),
GFP_KERNEL
);
if
(
!
mlp
)
return
-
ENOMEM
;
memset
(
mlp
,
0
,
sizeof
(
*
mlp
));
mlp
->
magic
=
ISDN_NET_MAGIC
;
INIT_LIST_HEAD
(
&
mlp
->
slaves
);
INIT_LIST_HEAD
(
&
mlp
->
online
);
mlp
->
p_encap
=
-
1
;
isdn_net_set_encap
(
mlp
,
ISDN_NET_ENCAP_RAWIP
);
mlp
->
l2_proto
=
ISDN_PROTO_L2_X75I
;
mlp
->
l3_proto
=
ISDN_PROTO_L3_TRANS
;
mlp
->
triggercps
=
6000
;
mlp
->
slavedelay
=
10
*
HZ
;
mlp
->
hupflags
=
ISDN_INHUP
;
mlp
->
onhtime
=
10
;
mlp
->
dialmax
=
1
;
mlp
->
flags
=
ISDN_NET_CBHUP
|
ISDN_NET_DM_MANUAL
;
mlp
->
cbdelay
=
5
*
HZ
;
/* Wait 5 secs before call-back */
mlp
->
dialtimeout
=
60
*
HZ
;
/* Wait 1 min for connection */
mlp
->
dialwait
=
5
*
HZ
;
/* Wait 5 sec. after failed dial */
INIT_LIST_HEAD
(
&
mlp
->
phone
[
0
]);
INIT_LIST_HEAD
(
&
mlp
->
phone
[
1
]);
dev
=
&
mlp
->
dev
;
}
idev
->
mlp
=
mlp
;
list_add_tail
(
&
idev
->
slaves
,
&
mlp
->
slaves
);
if
(
dev
)
{
strcpy
(
dev
->
name
,
name
);
dev
->
priv
=
mlp
;
dev
->
init
=
isdn_init_netif
;
SET_MODULE_OWNER
(
dev
);
retval
=
register_netdev
(
dev
);
if
(
retval
)
{
kfree
(
mlp
);
kfree
(
idev
);
return
retval
;
}
}
list_add
(
&
idev
->
global_list
,
&
isdn_net_devs
);
return
0
;
}
/*
* Add a new slave interface to an existing one
*/
static
int
isdn_net_addslave
(
char
*
parm
)
{
char
*
p
=
strchr
(
parm
,
','
);
isdn_net_dev
*
idev
;
isdn_net_local
*
mlp
;
int
retval
;
/* get slave name */
if
(
!
p
||
!
p
[
1
])
return
-
EINVAL
;
*
p
++
=
0
;
/* find master */
idev
=
isdn_net_findif
(
parm
);
if
(
!
idev
)
return
-
ESRCH
;
mlp
=
idev
->
mlp
;
rtnl_lock
();
if
(
netif_running
(
&
mlp
->
dev
))
return
-
EBUSY
;
retval
=
isdn_net_addif
(
p
,
mlp
);
rtnl_unlock
();
return
retval
;
}
/*
* Delete a single network-interface
*/
static
int
isdn_net_dev_delete
(
isdn_net_dev
*
idev
)
{
isdn_net_local
*
mlp
=
idev
->
mlp
;
int
retval
;
rtnl_lock
();
if
(
netif_running
(
&
mlp
->
dev
))
{
retval
=
-
EBUSY
;
goto
unlock
;
}
isdn_net_set_encap
(
mlp
,
-
1
);
isdn_net_rmallphone
(
idev
);
if
(
idev
->
exclusive
>=
0
)
isdn_unexclusive_channel
(
idev
->
pre_device
,
idev
->
pre_channel
);
list_del
(
&
idev
->
slaves
);
rtnl_unlock
();
if
(
list_empty
(
&
mlp
->
slaves
))
{
unregister_netdev
(
&
mlp
->
dev
);
kfree
(
mlp
);
}
list_del
(
&
idev
->
global_list
);
kfree
(
idev
);
return
0
;
unlock:
rtnl_unlock
();
return
retval
;
}
/*
* Delete a single network-interface
*/
static
int
isdn_net_delif
(
char
*
name
)
{
/* FIXME: For compatibility, if a master isdn_net_dev is rm'ed,
* kill all slaves, too */
isdn_net_dev
*
idev
=
isdn_net_findif
(
name
);
if
(
!
idev
)
return
-
ENODEV
;
return
isdn_net_dev_delete
(
idev
);
}
/*
* Set interface-parameters.
* Always set all parameters, so the user-level application is responsible
* for not overwriting existing setups. It has to get the current
* setup first, if only selected parameters are to be changed.
*/
static
int
isdn_net_setcfg
(
isdn_net_ioctl_cfg
*
cfg
)
{
isdn_net_dev
*
idev
=
isdn_net_findif
(
cfg
->
name
);
isdn_net_local
*
mlp
;
ulong
features
;
int
i
,
retval
;
if
(
!
idev
)
return
-
ENODEV
;
mlp
=
idev
->
mlp
;
rtnl_lock
();
if
(
netif_running
(
&
mlp
->
dev
))
{
retval
=
-
EBUSY
;
goto
out
;
}
/* See if any registered driver supports the features we want */
features
=
((
1
<<
cfg
->
l2_proto
)
<<
ISDN_FEATURE_L2_SHIFT
)
|
((
1
<<
cfg
->
l3_proto
)
<<
ISDN_FEATURE_L3_SHIFT
);
for
(
i
=
0
;
i
<
ISDN_MAX_DRIVERS
;
i
++
)
if
(
dev
->
drv
[
i
]
&&
(
dev
->
drv
[
i
]
->
interface
->
features
&
features
)
==
features
)
break
;
if
(
i
==
ISDN_MAX_DRIVERS
)
{
printk
(
KERN_WARNING
"isdn_net: No driver with selected features
\n
"
);
retval
=
-
ENODEV
;
goto
out
;
}
retval
=
isdn_net_set_encap
(
mlp
,
cfg
->
p_encap
);
if
(
retval
)
goto
out
;
retval
=
isdn_net_bind
(
idev
,
cfg
);
if
(
retval
)
goto
out
;
strncpy
(
mlp
->
msn
,
cfg
->
eaz
,
ISDN_MSNLEN
-
1
);
mlp
->
msn
[
ISDN_MSNLEN
-
1
]
=
0
;
mlp
->
onhtime
=
cfg
->
onhtime
;
idev
->
charge
=
cfg
->
charge
;
mlp
->
l2_proto
=
cfg
->
l2_proto
;
mlp
->
l3_proto
=
cfg
->
l3_proto
;
mlp
->
cbdelay
=
cfg
->
cbdelay
*
HZ
/
5
;
mlp
->
dialmax
=
cfg
->
dialmax
;
mlp
->
triggercps
=
cfg
->
triggercps
;
mlp
->
slavedelay
=
cfg
->
slavedelay
*
HZ
;
idev
->
pppbind
=
cfg
->
pppbind
;
mlp
->
dialtimeout
=
cfg
->
dialtimeout
>=
0
?
cfg
->
dialtimeout
*
HZ
:
-
1
;
mlp
->
dialwait
=
cfg
->
dialwait
*
HZ
;
if
(
cfg
->
secure
)
mlp
->
flags
|=
ISDN_NET_SECURE
;
else
mlp
->
flags
&=
~
ISDN_NET_SECURE
;
if
(
cfg
->
cbhup
)
mlp
->
flags
|=
ISDN_NET_CBHUP
;
else
mlp
->
flags
&=
~
ISDN_NET_CBHUP
;
switch
(
cfg
->
callback
)
{
case
0
:
mlp
->
flags
&=
~
(
ISDN_NET_CALLBACK
|
ISDN_NET_CBOUT
);
break
;
case
1
:
mlp
->
flags
|=
ISDN_NET_CALLBACK
;
mlp
->
flags
&=
~
ISDN_NET_CBOUT
;
break
;
case
2
:
mlp
->
flags
|=
ISDN_NET_CBOUT
;
mlp
->
flags
&=
~
ISDN_NET_CALLBACK
;
break
;
}
mlp
->
flags
&=
~
ISDN_NET_DIALMODE_MASK
;
/* first all bits off */
if
(
cfg
->
dialmode
&&
!
(
cfg
->
dialmode
&
ISDN_NET_DIALMODE_MASK
))
{
retval
=
-
EINVAL
;
goto
out
;
}
mlp
->
flags
|=
cfg
->
dialmode
;
/* turn on selected bits */
if
(
mlp
->
flags
&
ISDN_NET_DM_OFF
)
isdn_net_hangup
(
idev
);
if
(
cfg
->
chargehup
)
mlp
->
hupflags
|=
ISDN_CHARGEHUP
;
else
mlp
->
hupflags
&=
~
ISDN_CHARGEHUP
;
if
(
cfg
->
ihup
)
mlp
->
hupflags
|=
ISDN_INHUP
;
else
mlp
->
hupflags
&=
~
ISDN_INHUP
;
if
(
cfg
->
chargeint
>
10
)
{
idev
->
chargeint
=
cfg
->
chargeint
*
HZ
;
idev
->
charge_state
=
ST_CHARGE_HAVE_CINT
;
mlp
->
hupflags
|=
ISDN_MANCHARGE
;
}
retval
=
0
;
out:
rtnl_unlock
();
return
retval
;
}
/*
* Perform get-interface-parameters.ioctl
*/
static
int
isdn_net_getcfg
(
isdn_net_ioctl_cfg
*
cfg
)
{
isdn_net_dev
*
idev
=
isdn_net_findif
(
cfg
->
name
);
isdn_net_local
*
mlp
;
if
(
!
idev
)
return
-
ENODEV
;
mlp
=
idev
->
mlp
;
strcpy
(
cfg
->
eaz
,
mlp
->
msn
);
cfg
->
exclusive
=
idev
->
exclusive
>=
0
;
if
(
idev
->
pre_device
>=
0
)
{
sprintf
(
cfg
->
drvid
,
"%s,%d"
,
dev
->
drvid
[
idev
->
pre_device
],
idev
->
pre_channel
);
}
else
{
cfg
->
drvid
[
0
]
=
'\0'
;
}
cfg
->
onhtime
=
mlp
->
onhtime
;
cfg
->
charge
=
idev
->
charge
;
cfg
->
l2_proto
=
mlp
->
l2_proto
;
cfg
->
l3_proto
=
mlp
->
l3_proto
;
cfg
->
p_encap
=
mlp
->
p_encap
;
cfg
->
secure
=
(
mlp
->
flags
&
ISDN_NET_SECURE
)
?
1
:
0
;
cfg
->
callback
=
0
;
if
(
mlp
->
flags
&
ISDN_NET_CALLBACK
)
cfg
->
callback
=
1
;
if
(
mlp
->
flags
&
ISDN_NET_CBOUT
)
cfg
->
callback
=
2
;
cfg
->
cbhup
=
(
mlp
->
flags
&
ISDN_NET_CBHUP
)
?
1
:
0
;
cfg
->
dialmode
=
mlp
->
flags
&
ISDN_NET_DIALMODE_MASK
;
cfg
->
chargehup
=
(
mlp
->
hupflags
&
ISDN_CHARGEHUP
)
?
1
:
0
;
cfg
->
ihup
=
(
mlp
->
hupflags
&
ISDN_INHUP
)
?
1
:
0
;
cfg
->
cbdelay
=
mlp
->
cbdelay
*
5
/
HZ
;
cfg
->
dialmax
=
mlp
->
dialmax
;
cfg
->
triggercps
=
mlp
->
triggercps
;
cfg
->
slavedelay
=
mlp
->
slavedelay
/
HZ
;
cfg
->
chargeint
=
(
mlp
->
hupflags
&
ISDN_CHARGEHUP
)
?
(
idev
->
chargeint
/
HZ
)
:
0
;
cfg
->
pppbind
=
idev
->
pppbind
;
cfg
->
dialtimeout
=
mlp
->
dialtimeout
>=
0
?
mlp
->
dialtimeout
/
HZ
:
-
1
;
cfg
->
dialwait
=
mlp
->
dialwait
/
HZ
;
if
(
idev
->
slaves
.
next
!=
&
mlp
->
slaves
)
strcpy
(
cfg
->
slave
,
list_entry
(
idev
->
slaves
.
next
,
isdn_net_dev
,
slaves
)
->
name
);
else
cfg
->
slave
[
0
]
=
'\0'
;
if
(
strcmp
(
mlp
->
dev
.
name
,
idev
->
name
))
strcpy
(
cfg
->
master
,
mlp
->
dev
.
name
);
else
cfg
->
master
[
0
]
=
'\0'
;
return
0
;
}
/*
* Add a phone-number to an interface.
*/
static
int
isdn_net_addphone
(
isdn_net_ioctl_phone
*
phone
)
{
isdn_net_dev
*
idev
=
isdn_net_findif
(
phone
->
name
);
struct
isdn_net_phone
*
n
;
int
retval
=
0
;
if
(
!
idev
)
return
-
ENODEV
;
rtnl_lock
();
if
(
netif_running
(
&
idev
->
mlp
->
dev
))
{
retval
=
-
EBUSY
;
goto
out
;
}
n
=
kmalloc
(
sizeof
(
*
n
),
GFP_KERNEL
);
if
(
!
n
)
{
retval
=
-
ENOMEM
;
goto
out
;
}
strcpy
(
n
->
num
,
phone
->
phone
);
list_add_tail
(
&
n
->
list
,
&
idev
->
mlp
->
phone
[
phone
->
outgoing
&
1
]);
out:
rtnl_unlock
();
return
retval
;
}
/*
* Delete a phone-number from an interface.
*/
static
int
isdn_net_delphone
(
isdn_net_ioctl_phone
*
phone
)
{
isdn_net_dev
*
idev
=
isdn_net_findif
(
phone
->
name
);
struct
isdn_net_phone
*
n
;
int
retval
;
if
(
!
idev
)
return
-
ENODEV
;
rtnl_lock
();
if
(
netif_running
(
&
idev
->
mlp
->
dev
))
{
retval
=
-
EBUSY
;
goto
out
;
}
retval
=
-
EINVAL
;
list_for_each_entry
(
n
,
&
idev
->
mlp
->
phone
[
phone
->
outgoing
&
1
],
list
)
{
if
(
!
strcmp
(
n
->
num
,
phone
->
phone
))
{
list_del
(
&
n
->
list
);
kfree
(
n
);
retval
=
0
;
break
;
}
}
out:
rtnl_unlock
();
return
retval
;
}
/*
* Copy a string of all phone-numbers of an interface to user space.
*/
static
int
isdn_net_getphone
(
isdn_net_ioctl_phone
*
phone
,
char
*
phones
)
{
isdn_net_dev
*
idev
=
isdn_net_findif
(
phone
->
name
);
int
count
=
0
;
char
*
buf
=
(
char
*
)
__get_free_page
(
GFP_KERNEL
);
struct
isdn_net_phone
*
n
;
if
(
!
buf
)
return
-
ENOMEM
;
if
(
!
idev
)
{
count
=
-
ENODEV
;
goto
free
;
}
list_for_each_entry
(
n
,
&
idev
->
mlp
->
phone
[
phone
->
outgoing
&
1
],
list
)
{
strcpy
(
&
buf
[
count
],
n
->
num
);
count
+=
strlen
(
n
->
num
);
buf
[
count
++
]
=
' '
;
if
(
count
>
PAGE_SIZE
-
ISDN_MSNLEN
-
1
)
break
;
}
if
(
!
count
)
/* list was empty? */
count
++
;
buf
[
count
-
1
]
=
0
;
if
(
copy_to_user
(
phones
,
buf
,
count
))
count
=
-
EFAULT
;
free:
free_page
((
unsigned
long
)
buf
);
return
count
;
}
/*
* Force a net-interface to dial out.
*/
static
int
isdn_net_dial_out
(
char
*
name
)
{
isdn_net_dev
*
idev
=
isdn_net_findif
(
name
);
if
(
!
idev
)
return
-
ENODEV
;
return
isdn_net_dial
(
idev
);
}
/*
* Force a hangup of a network-interface.
*/
static
int
isdn_net_force_hangup
(
char
*
name
)
// FIXME rename?
{
isdn_net_dev
*
idev
=
isdn_net_findif
(
name
);
if
(
!
idev
)
return
-
ENODEV
;
if
(
idev
->
isdn_slot
<
0
)
return
-
ENOTCONN
;
isdn_net_hangup
(
idev
);
return
0
;
}
/*
* Copy a string containing the peer's phone number of a connected interface
* to user space.
*/
static
int
isdn_net_getpeer
(
isdn_net_ioctl_phone
*
phone
,
isdn_net_ioctl_phone
*
peer
)
{
isdn_net_dev
*
idev
=
isdn_net_findif
(
phone
->
name
);
int
idx
;
if
(
!
idev
)
return
-
ENODEV
;
/* FIXME
* Theoretical race: while this executes, the remote number might
* become invalid (hang up) or change (new connection), resulting
* in (partially) wrong number copied to user. This race
* currently ignored.
*/
idx
=
idev
->
isdn_slot
;
if
(
idx
<
0
)
return
-
ENOTCONN
;
/* for pre-bound channels, we need this extra check */
if
(
strncmp
(
isdn_slot_num
(
idx
),
"???"
,
3
)
==
0
)
return
-
ENOTCONN
;
strncpy
(
phone
->
phone
,
isdn_slot_num
(
idx
),
ISDN_MSNLEN
);
phone
->
outgoing
=
USG_OUTGOING
(
isdn_slot_usage
(
idx
));
if
(
copy_to_user
(
peer
,
phone
,
sizeof
(
*
peer
)))
return
-
EFAULT
;
return
0
;
}
/*
* ioctl on /dev/isdnctrl, used to configure ISDN net interfaces
*/
int
isdn_net_ioctl
(
struct
inode
*
ino
,
struct
file
*
file
,
uint
cmd
,
ulong
arg
)
{
/* Save stack space */
union
{
char
name
[
10
];
char
bname
[
20
];
isdn_net_ioctl_phone
phone
;
isdn_net_ioctl_cfg
cfg
;
}
iocpar
;
int
retval
;
#define name iocpar.name
#define bname iocpar.bname
#define phone iocpar.phone
#define cfg iocpar.cfg
name
[
sizeof
(
name
)
-
1
]
=
0
;
bname
[
sizeof
(
bname
)
-
1
]
=
0
;
down
(
&
sem
);
switch
(
cmd
)
{
case
IIOCNETAIF
:
/* add an interface */
if
(
copy_from_user
(
name
,
(
char
*
)
arg
,
sizeof
(
name
)
-
1
))
{
retval
=
-
EFAULT
;
break
;
}
retval
=
isdn_net_addif
(
name
,
NULL
);
break
;
case
IIOCNETASL
:
/* add slave to an interface */
if
(
copy_from_user
(
bname
,
(
char
*
)
arg
,
sizeof
(
bname
)
-
1
))
{
retval
=
-
EFAULT
;
break
;
}
retval
=
isdn_net_addslave
(
bname
);
break
;
case
IIOCNETDIF
:
/* delete an interface */
if
(
copy_from_user
(
name
,
(
char
*
)
arg
,
sizeof
(
name
)
-
1
))
{
retval
=
-
EFAULT
;
break
;
}
retval
=
isdn_net_delif
(
name
);
break
;
case
IIOCNETSCF
:
/* set config */
if
(
copy_from_user
((
char
*
)
&
cfg
,
(
char
*
)
arg
,
sizeof
(
cfg
)))
{
retval
=
-
EFAULT
;
break
;
}
retval
=
isdn_net_setcfg
(
&
cfg
);
break
;
case
IIOCNETGCF
:
/* get config */
if
(
copy_from_user
((
char
*
)
&
cfg
,
(
char
*
)
arg
,
sizeof
(
cfg
)))
{
retval
=
-
EFAULT
;
break
;
}
retval
=
isdn_net_getcfg
(
&
cfg
);
if
(
retval
)
break
;
if
(
copy_to_user
((
char
*
)
arg
,
(
char
*
)
&
cfg
,
sizeof
(
cfg
)))
retval
=
-
EFAULT
;
break
;
case
IIOCNETANM
:
/* add a phone number */
if
(
copy_from_user
((
char
*
)
&
phone
,
(
char
*
)
arg
,
sizeof
(
phone
)))
{
retval
=
-
EFAULT
;
break
;
}
retval
=
isdn_net_addphone
(
&
phone
);
break
;
case
IIOCNETGNM
:
/* get list of phone numbers */
if
(
copy_from_user
((
char
*
)
&
phone
,
(
char
*
)
arg
,
sizeof
(
phone
)))
{
retval
=
-
EFAULT
;
break
;
}
retval
=
isdn_net_getphone
(
&
phone
,
(
char
*
)
arg
);
break
;
case
IIOCNETDNM
:
/* delete a phone number */
if
(
copy_from_user
((
char
*
)
&
phone
,
(
char
*
)
arg
,
sizeof
(
phone
)))
{
retval
=
-
EFAULT
;
break
;
}
retval
=
isdn_net_delphone
(
&
phone
);
break
;
case
IIOCNETDIL
:
/* trigger dial-out */
if
(
copy_from_user
(
name
,
(
char
*
)
arg
,
sizeof
(
name
)))
{
retval
=
-
EFAULT
;
break
;
}
retval
=
isdn_net_dial_out
(
name
);
break
;
case
IIOCNETHUP
:
/* hangup */
if
(
copy_from_user
(
name
,
(
char
*
)
arg
,
sizeof
(
name
)))
{
retval
=
-
EFAULT
;
break
;
}
retval
=
isdn_net_force_hangup
(
name
);
break
;
case
IIOCNETGPN
:
/* Get peer phone number of a connected interface */
if
(
copy_from_user
((
char
*
)
&
phone
,
(
char
*
)
arg
,
sizeof
(
phone
)))
{
retval
=
-
EFAULT
;
}
retval
=
isdn_net_getpeer
(
&
phone
,
(
isdn_net_ioctl_phone
*
)
arg
);
break
;
#ifdef CONFIG_ISDN_PPP
case
IIOCNETALN
:
/* Add link */
if
(
copy_from_user
(
name
,
(
char
*
)
arg
,
sizeof
(
name
)))
{
retval
=
-
EFAULT
;
break
;
}
retval
=
isdn_ppp_dial_slave
(
name
);
break
;
case
IIOCNETDLN
:
/* Delete link */
if
(
copy_from_user
(
name
,
(
char
*
)
arg
,
sizeof
(
name
)))
{
retval
=
-
EFAULT
;
break
;
}
retval
=
isdn_ppp_hangup_slave
(
name
);
break
;
#endif
default:
retval
=
-
ENOTTY
;
}
up
(
&
sem
);
return
retval
;
#undef name
#undef bname
#undef iocts
#undef phone
#undef cfg
}
/*
* Hang up all network-interfaces
*/
void
isdn_net_hangup_all
(
void
)
{
isdn_net_dev
*
idev
;
down
(
&
sem
);
list_for_each_entry
(
idev
,
&
isdn_net_devs
,
global_list
)
isdn_net_hangup
(
idev
);
up
(
&
sem
);
}
/*
* Remove all network-interfaces
*/
void
isdn_net_exit
(
void
)
{
isdn_net_dev
*
idev
;
int
retval
;
down
(
&
sem
);
while
(
!
list_empty
(
&
isdn_net_devs
))
{
idev
=
list_entry
(
isdn_net_devs
.
next
,
isdn_net_dev
,
global_list
);
retval
=
isdn_net_dev_delete
(
idev
);
/* can only fail if an interface is still running.
* In this case, an elevated module use count should
* have prevented this function from being called in
* the first place */
if
(
retval
)
isdn_BUG
();
}
up
(
&
sem
);
// FIXME
isdn_net_lib_exit
();
}
/* ====================================================================== */
/* interface to network layer */
/* ====================================================================== */
/*
* Open/initialize the board.
*/
static
int
isdn_net_open
(
struct
net_device
*
dev
)
{
isdn_net_local
*
lp
=
dev
->
priv
;
int
retval
=
0
;
if
(
!
lp
->
ops
)
return
-
ENODEV
;
if
(
lp
->
ops
->
open
)
retval
=
lp
->
ops
->
open
(
lp
);
if
(
!
retval
)
return
retval
;
netif_start_queue
(
dev
);
return
0
;
}
/*
* Shutdown a net-interface.
*/
// FIXME share?
static
int
isdn_net_close
(
struct
net_device
*
dev
)
{
isdn_net_local
*
lp
=
dev
->
priv
;
struct
list_head
*
l
,
*
n
;
isdn_net_dev
*
sdev
;
if
(
lp
->
ops
->
close
)
lp
->
ops
->
close
(
lp
);
netif_stop_queue
(
dev
);
list_for_each_safe
(
l
,
n
,
&
lp
->
online
)
{
sdev
=
list_entry
(
l
,
isdn_net_dev
,
online
);
isdn_net_hangup
(
sdev
);
}
return
0
;
}
/*
* Get statistics
*/
static
struct
net_device_stats
*
isdn_net_get_stats
(
struct
net_device
*
dev
)
{
isdn_net_local
*
lp
=
dev
->
priv
;
return
&
lp
->
stats
;
}
/*
* Transmit timeout
*/
static
void
isdn_net_tx_timeout
(
struct
net_device
*
dev
)
{
printk
(
KERN_WARNING
"isdn_tx_timeout dev %s
\n
"
,
dev
->
name
);
netif_wake_queue
(
dev
);
}
/*
* Interface-setup. (just after registering a new interface)
*/
static
int
isdn_init_netif
(
struct
net_device
*
ndev
)
{
/* Setup the generic properties */
ndev
->
mtu
=
1500
;
ndev
->
tx_queue_len
=
10
;
ndev
->
open
=
&
isdn_net_open
;
ndev
->
hard_header_len
=
ETH_HLEN
+
isdn_hard_header_len
();
ndev
->
stop
=
&
isdn_net_close
;
ndev
->
get_stats
=
&
isdn_net_get_stats
;
ndev
->
tx_timeout
=
isdn_net_tx_timeout
;
ndev
->
watchdog_timeo
=
ISDN_NET_TX_TIMEOUT
;
return
0
;
}
/* ====================================================================== */
static
void
isdn_net_tasklet
(
unsigned
long
data
)
{
isdn_net_dev
*
idev
=
(
isdn_net_dev
*
)
data
;
struct
sk_buff
*
skb
;
spin_lock_bh
(
&
idev
->
xmit_lock
);
while
(
!
isdn_net_dev_busy
(
idev
))
{
skb
=
skb_dequeue
(
&
idev
->
super_tx_queue
);
if
(
!
skb
)
break
;
isdn_net_writebuf_skb
(
idev
,
skb
);
}
spin_unlock_bh
(
&
idev
->
xmit_lock
);
}
/* ====================================================================== */
/* call control state machine */
/* ====================================================================== */
static
void
dialout_first
(
struct
fsm_inst
*
fi
,
int
pr
,
void
*
arg
);
static
void
dialout_next
(
struct
fsm_inst
*
fi
,
int
pr
,
void
*
arg
);
// FIXME
int
isdn_net_online
(
isdn_net_dev
*
idev
)
{
return
idev
->
fi
.
state
==
ST_ACTIVE
;
}
static
void
isdn_net_dial_timer
(
unsigned
long
data
)
{
isdn_net_dev
*
idev
=
(
isdn_net_dev
*
)
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
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
();
return
;
}
if
(
mlp
->
ops
->
unbind
)
mlp
->
ops
->
unbind
(
idev
);
skb_queue_purge
(
&
idev
->
super_tx_queue
);
fsm_change_state
(
&
idev
->
fi
,
ST_NULL
);
isdn_slot_set_idev
(
idev
->
isdn_slot
,
NULL
);
isdn_slot_free
(
idev
->
isdn_slot
,
ISDN_USAGE_NET
);
idev
->
isdn_slot
=
-
1
;
restore_flags
(
flags
);
}
int
isdn_net_dial
(
isdn_net_dev
*
idev
)
{
int
slot
;
isdn_net_local
*
mlp
=
idev
->
mlp
;
if
(
isdn_net_bound
(
idev
))
return
-
EBUSY
;
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
;
isdn_slot_set_usage
(
slot
,
isdn_slot_usage
(
slot
)
|
ISDN_USAGE_OUTGOING
);
if
(
isdn_net_bind_channel
(
idev
,
slot
)
<
0
)
goto
err
;
/* Initiate dialing */
dialout_first
(
&
idev
->
fi
,
0
,
NULL
);
// FIXME
return
0
;
err:
return
-
EAGAIN
;
}
void
isdn_net_accept
(
isdn_net_dev
*
idev
,
int
slot
,
char
*
nr
)
{
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
);
isdn_net_bind_channel
(
idev
,
slot
);
idev
->
outgoing
=
0
;
idev
->
charge_state
=
ST_CHARGE_NULL
;
/* Got incoming Call, setup L2 and L3 protocols,
* then wait for D-Channel-connect
*/
cmd
.
arg
=
mlp
->
l2_proto
<<
8
;
isdn_slot_command
(
idev
->
isdn_slot
,
ISDN_CMD_SETL2
,
&
cmd
);
cmd
.
arg
=
mlp
->
l3_proto
<<
8
;
isdn_slot_command
(
idev
->
isdn_slot
,
ISDN_CMD_SETL3
,
&
cmd
);
idev
->
dial_timer
.
expires
=
jiffies
+
mlp
->
dialtimeout
;
idev
->
dial_event
=
EV_TIMER_INCOMING
;
add_timer
(
&
idev
->
dial_timer
);
fsm_change_state
(
&
idev
->
fi
,
ST_IN_WAIT_DCONN
);
}
int
isdn_net_do_callback
(
isdn_net_dev
*
idev
)
{
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
;
/* 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
);
/* Initiate dialing by returning 2 or 4 */
return
(
mlp
->
flags
&
ISDN_NET_CBHUP
)
?
2
:
4
;
err:
return
0
;
}
/* ---------------------------------------------------------------------- */
/* callbacks in the state machine */
/* ---------------------------------------------------------------------- */
/* Find the idev->dial'th outgoing number. */
static
struct
isdn_net_phone
*
get_outgoing_phone
(
isdn_net_dev
*
idev
)
{
isdn_net_local
*
mlp
=
idev
->
mlp
;
struct
isdn_net_phone
*
phone
;
int
i
=
0
;
list_for_each_entry
(
phone
,
&
mlp
->
phone
[
1
],
list
)
{
if
(
i
++
==
idev
->
dial
)
return
phone
;
}
return
NULL
;
}
/* Initiate dialout. */
static
void
dialout_first
(
struct
fsm_inst
*
fi
,
int
pr
,
void
*
arg
)
{
isdn_net_dev
*
idev
=
fi
->
userdata
;
isdn_net_local
*
mlp
=
idev
->
mlp
;
if
(
ISDN_NET_DIALMODE
(
*
mlp
)
==
ISDN_NET_DM_OFF
)
{
isdn_net_unbind_channel
(
idev
);
return
;
}
if
(
list_empty
(
&
mlp
->
phone
[
1
]))
{
isdn_net_unbind_channel
(
idev
);
return
;
}
idev
->
dial
=
0
;
idev
->
dialretry
=
0
;
dialout_next
(
fi
,
pr
,
arg
);
}
/* Try dialing the next number. */
static
void
dialout_next
(
struct
fsm_inst
*
fi
,
int
pr
,
void
*
arg
)
{
isdn_net_dev
*
idev
=
fi
->
userdata
;
isdn_net_local
*
mlp
=
idev
->
mlp
;
struct
dial_info
dial
=
{
.
l2_proto
=
mlp
->
l2_proto
,
.
l3_proto
=
mlp
->
l3_proto
,
.
si1
=
7
,
.
si2
=
0
,
.
msn
=
mlp
->
msn
,
.
phone
=
get_outgoing_phone
(
idev
)
->
num
,
};
/* next time, try next number */
idev
->
dial
++
;
idev
->
outgoing
=
1
;
if
(
idev
->
chargeint
)
idev
->
charge_state
=
ST_CHARGE_HAVE_CINT
;
else
idev
->
charge_state
=
ST_CHARGE_NULL
;
/* For outgoing callback, use cbdelay instead of dialtimeout */
if
(
mlp
->
cbdelay
&&
(
mlp
->
flags
&
ISDN_NET_CBOUT
))
{
idev
->
dial_timer
.
expires
=
jiffies
+
mlp
->
cbdelay
;
idev
->
dial_event
=
EV_TIMER_CB_OUT
;
}
else
{
idev
->
dial_timer
.
expires
=
jiffies
+
mlp
->
dialtimeout
;
idev
->
dial_event
=
EV_TIMER_DIAL
;
}
fsm_change_state
(
&
idev
->
fi
,
ST_OUT_WAIT_DCONN
);
add_timer
(
&
idev
->
dial_timer
);
/* Dial */
isdn_slot_dial
(
idev
->
isdn_slot
,
&
dial
);
}
/* If we didn't connect within dialtimeout, we give up for now
* and wait for dialwait jiffies before trying again.
*/
static
void
dial_timeout
(
struct
fsm_inst
*
fi
,
int
pr
,
void
*
arg
)
{
isdn_net_dev
*
idev
=
fi
->
userdata
;
isdn_net_local
*
mlp
=
idev
->
mlp
;
isdn_ctrl
cmd
;
fsm_change_state
(
&
idev
->
fi
,
ST_OUT_DIAL_WAIT
);
isdn_slot_command
(
idev
->
isdn_slot
,
ISDN_CMD_HANGUP
,
&
cmd
);
/* get next phone number */
if
(
!
get_outgoing_phone
(
idev
))
{
/* otherwise start over at first entry */
idev
->
dial
=
0
;
idev
->
dialretry
++
;
}
if
(
idev
->
dialretry
>=
mlp
->
dialmax
)
{
isdn_net_hangup
(
idev
);
return
;
}
idev
->
dial_event
=
EV_TIMER_DIAL_WAIT
;
mod_timer
(
&
idev
->
dial_timer
,
jiffies
+
mlp
->
dialwait
);
}
static
void
connect_fail
(
struct
fsm_inst
*
fi
,
int
pr
,
void
*
arg
)
{
isdn_net_dev
*
idev
=
fi
->
userdata
;
del_timer
(
&
idev
->
dial_timer
);
isdn_slot_all_eaz
(
idev
->
isdn_slot
);
printk
(
KERN_INFO
"%s: connection failed
\n
"
,
idev
->
name
);
isdn_net_unbind_channel
(
idev
);
}
static
void
out_dconn
(
struct
fsm_inst
*
fi
,
int
pr
,
void
*
arg
)
{
isdn_net_dev
*
idev
=
fi
->
userdata
;
isdn_ctrl
cmd
;
fsm_change_state
(
&
idev
->
fi
,
ST_OUT_WAIT_BCONN
);
isdn_slot_command
(
idev
->
isdn_slot
,
ISDN_CMD_ACCEPTB
,
&
cmd
);
}
static
void
in_dconn
(
struct
fsm_inst
*
fi
,
int
pr
,
void
*
arg
)
{
isdn_net_dev
*
idev
=
fi
->
userdata
;
isdn_ctrl
cmd
;
fsm_change_state
(
&
idev
->
fi
,
ST_IN_WAIT_BCONN
);
isdn_slot_command
(
idev
->
isdn_slot
,
ISDN_CMD_ACCEPTB
,
&
cmd
);
}
static
void
bconn
(
struct
fsm_inst
*
fi
,
int
pr
,
void
*
arg
)
{
isdn_net_dev
*
idev
=
fi
->
userdata
;
isdn_net_local
*
mlp
=
idev
->
mlp
;
fsm_change_state
(
&
idev
->
fi
,
ST_ACTIVE
);
if
(
mlp
->
onhtime
)
{
idev
->
huptimer
=
0
;
idev
->
dial_event
=
EV_TIMER_HUP
;
mod_timer
(
&
idev
->
dial_timer
,
jiffies
+
HZ
);
}
else
{
del_timer
(
&
idev
->
dial_timer
);
}
isdn_net_add_to_bundle
(
mlp
,
idev
);
printk
(
KERN_INFO
"isdn_net: %s connected
\n
"
,
idev
->
name
);
/* If first Chargeinfo comes before B-Channel connect,
* we correct the timestamp here.
*/
idev
->
chargetime
=
jiffies
;
idev
->
transcount
=
0
;
idev
->
cps
=
0
;
idev
->
last_jiffies
=
jiffies
;
if
(
mlp
->
ops
->
connected
)
mlp
->
ops
->
connected
(
idev
);
else
isdn_net_dev_wake_queue
(
idev
);
}
/* Check if it's time for idle hang-up */
static
void
check_hup
(
struct
fsm_inst
*
fi
,
int
pr
,
void
*
arg
)
{
isdn_net_dev
*
idev
=
fi
->
userdata
;
isdn_net_local
*
mlp
=
idev
->
mlp
;
dbg_net_dial
(
"%s: huptimer %d onhtime %d chargetime %ld chargeint %d
\n
"
,
idev
->
name
,
idev
->
huptimer
,
mlp
->
onhtime
,
idev
->
chargetime
,
idev
->
chargeint
);
if
(
idev
->
huptimer
++
<=
mlp
->
onhtime
)
goto
mod_timer
;
if
(
mlp
->
hupflags
&
ISDN_CHARGEHUP
&&
idev
->
charge_state
==
ST_CHARGE_HAVE_CINT
)
{
if
(
!
time_after
(
jiffies
,
idev
->
chargetime
+
idev
->
chargeint
-
2
*
HZ
))
goto
mod_timer
;
}
if
(
idev
->
outgoing
||
mlp
->
hupflags
&
ISDN_INHUP
)
{
isdn_net_hangup
(
idev
);
return
;
}
mod_timer:
mod_timer
(
&
idev
->
dial_timer
,
idev
->
dial_timer
.
expires
+
HZ
);
}
/* Charge-info from TelCo. */
static
void
got_cinf
(
struct
fsm_inst
*
fi
,
int
pr
,
void
*
arg
)
{
isdn_net_dev
*
idev
=
fi
->
userdata
;
idev
->
charge
++
;
switch
(
idev
->
charge_state
)
{
case
ST_CHARGE_NULL
:
idev
->
charge_state
=
ST_CHARGE_GOT_CINF
;
break
;
case
ST_CHARGE_GOT_CINF
:
idev
->
charge_state
=
ST_CHARGE_HAVE_CINT
;
/* fall through */
case
ST_CHARGE_HAVE_CINT
:
idev
->
chargeint
=
jiffies
-
idev
->
chargetime
;
break
;
}
idev
->
chargetime
=
jiffies
;
dbg_net_dial
(
"%s: got CINF
\n
"
,
idev
->
name
);
}
static
void
disconnected
(
struct
fsm_inst
*
fi
,
int
pr
,
void
*
arg
)
{
isdn_net_dev
*
idev
=
fi
->
userdata
;
isdn_net_local
*
mlp
=
idev
->
mlp
;
del_timer
(
&
idev
->
dial_timer
);
if
(
mlp
->
ops
->
disconnected
)
mlp
->
ops
->
disconnected
(
idev
);
isdn_net_rm_from_bundle
(
idev
);
printk
(
KERN_INFO
"%s: disconnected
\n
"
,
idev
->
name
);
printk
(
KERN_INFO
"%s: Chargesum is %d
\n
"
,
idev
->
name
,
idev
->
charge
);
isdn_slot_all_eaz
(
idev
->
isdn_slot
);
isdn_net_unbind_channel
(
idev
);
}
/* Perform hangup for a net-interface. */
int
isdn_net_hangup
(
isdn_net_dev
*
idev
)
{
isdn_ctrl
cmd
;
del_timer
(
&
idev
->
dial_timer
);
if
(
!
isdn_net_bound
(
idev
))
{
isdn_BUG
();
return
1
;
}
printk
(
KERN_INFO
"%s: local hangup
\n
"
,
idev
->
name
);
isdn_slot_command
(
idev
->
isdn_slot
,
ISDN_CMD_HANGUP
,
&
cmd
);
return
1
;
}
/*
* Handle status-messages from ISDN-interfacecard.
* This function is called from within the main-status-dispatcher
* isdn_status_callback, which itself is called from the low-level driver.
* Return: 1 = event handled, 0 = not handled
*/
int
isdn_net_stat_callback
(
int
idx
,
isdn_ctrl
*
c
)
{
isdn_net_dev
*
idev
=
isdn_slot_idev
(
idx
);
if
(
!
idev
)
{
HERE
;
return
0
;
}
switch
(
c
->
command
)
{
case
ISDN_STAT_DCONN
:
return
fsm_event
(
&
idev
->
fi
,
EV_STAT_DCONN
,
c
);
case
ISDN_STAT_BCONN
:
return
fsm_event
(
&
idev
->
fi
,
EV_STAT_BCONN
,
c
);
case
ISDN_STAT_BHUP
:
return
fsm_event
(
&
idev
->
fi
,
EV_STAT_BHUP
,
c
);
case
ISDN_STAT_DHUP
:
return
fsm_event
(
&
idev
->
fi
,
EV_STAT_DHUP
,
c
);
case
ISDN_STAT_CINF
:
return
fsm_event
(
&
idev
->
fi
,
EV_STAT_CINF
,
c
);
case
ISDN_STAT_BSENT
:
return
fsm_event
(
&
idev
->
fi
,
EV_STAT_BSENT
,
c
);
default:
printk
(
"unknown stat %d
\n
"
,
c
->
command
);
return
0
;
}
}
int
isdn_net_handle_event
(
isdn_net_dev
*
idev
,
int
pr
,
void
*
arg
)
{
fsm_event
(
&
idev
->
fi
,
pr
,
arg
);
}
static
void
hang_up
(
struct
fsm_inst
*
fi
,
int
pr
,
void
*
arg
)
{
isdn_net_dev
*
idev
=
fi
->
userdata
;
isdn_net_hangup
(
idev
);
}
static
void
got_bsent
(
struct
fsm_inst
*
fi
,
int
pr
,
void
*
arg
)
{
isdn_net_dev
*
idev
=
fi
->
userdata
;
isdn_ctrl
*
c
=
arg
;
isdn_net_bsent
(
idev
,
c
);
}
static
struct
fsm_node
isdn_net_fn_tbl
[]
=
{
{
ST_OUT_WAIT_DCONN
,
EV_TIMER_DIAL
,
dial_timeout
},
{
ST_OUT_WAIT_DCONN
,
EV_STAT_DCONN
,
out_dconn
},
{
ST_OUT_WAIT_DCONN
,
EV_STAT_DHUP
,
connect_fail
},
{
ST_OUT_WAIT_DCONN
,
EV_TIMER_CB_OUT
,
hang_up
},
{
ST_OUT_WAIT_BCONN
,
EV_TIMER_DIAL
,
dial_timeout
},
{
ST_OUT_WAIT_BCONN
,
EV_STAT_BCONN
,
bconn
},
{
ST_OUT_WAIT_BCONN
,
EV_STAT_DHUP
,
connect_fail
},
{
ST_IN_WAIT_DCONN
,
EV_TIMER_INCOMING
,
hang_up
},
{
ST_IN_WAIT_DCONN
,
EV_STAT_DCONN
,
in_dconn
},
{
ST_IN_WAIT_DCONN
,
EV_STAT_DHUP
,
connect_fail
},
{
ST_IN_WAIT_BCONN
,
EV_TIMER_INCOMING
,
hang_up
},
{
ST_IN_WAIT_BCONN
,
EV_STAT_BCONN
,
bconn
},
{
ST_IN_WAIT_BCONN
,
EV_STAT_DHUP
,
connect_fail
},
{
ST_ACTIVE
,
EV_TIMER_HUP
,
check_hup
},
{
ST_ACTIVE
,
EV_STAT_BHUP
,
disconnected
},
{
ST_ACTIVE
,
EV_STAT_CINF
,
got_cinf
},
{
ST_ACTIVE
,
EV_STAT_BSENT
,
got_bsent
},
{
ST_WAIT_BEFORE_CB
,
EV_TIMER_CB_IN
,
dialout_first
},
{
ST_OUT_DIAL_WAIT
,
EV_TIMER_DIAL_WAIT
,
dialout_next
},
};
static
struct
fsm
isdn_net_fsm
=
{
.
st_cnt
=
ARRAY_SIZE
(
isdn_net_st_str
),
.
st_str
=
isdn_net_st_str
,
.
ev_cnt
=
ARRAY_SIZE
(
isdn_net_ev_str
),
.
ev_str
=
isdn_net_ev_str
,
.
fn_cnt
=
ARRAY_SIZE
(
isdn_net_fn_tbl
),
.
fn_tbl
=
isdn_net_fn_tbl
,
};
static
void
isdn_net_dev_debug
(
struct
fsm_inst
*
fi
,
char
*
fmt
,
...)
{
va_list
args
;
isdn_net_dev
*
idev
=
fi
->
userdata
;
char
buf
[
128
];
char
*
p
=
buf
;
va_start
(
args
,
fmt
);
p
+=
sprintf
(
p
,
"%s: "
,
idev
->
name
);
p
+=
vsprintf
(
p
,
fmt
,
args
);
va_end
(
args
);
printk
(
KERN_DEBUG
"%s
\n
"
,
buf
);
}
void
isdn_net_lib_init
(
void
)
{
fsm_new
(
&
isdn_net_fsm
);
}
void
isdn_net_lib_exit
(
void
)
{
fsm_free
(
&
isdn_net_fsm
);
}
drivers/isdn/i4l/isdn_ppp.c
View file @
994b6e06
...
...
@@ -23,7 +23,7 @@
/* Prototypes */
static
int
isdn_ppp_fill_rq
(
unsigned
char
*
buf
,
int
len
,
int
proto
,
int
slot
);
static
int
isdn_ppp_closewait
(
int
slot
);
static
void
isdn_ppp_push_higher
(
isdn_net_
dev
*
net_dev
,
isdn_net_local
*
lp
,
static
void
isdn_ppp_push_higher
(
isdn_net_
local
*
lp
,
isdn_net_dev
*
idev
,
struct
sk_buff
*
skb
,
int
proto
);
static
int
isdn_ppp_if_get_unit
(
char
*
namebuf
);
static
int
isdn_ppp_set_compressor
(
struct
ippp_struct
*
is
,
struct
isdn_ppp_comp_data
*
);
...
...
@@ -59,10 +59,10 @@ static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
static
ippp_bundle
*
isdn_ppp_bundle_arr
=
NULL
;
static
int
isdn_ppp_mp_bundle_array_init
(
void
);
static
int
isdn_ppp_mp_init
(
isdn_net_local
*
lp
,
ippp_bundle
*
add_to
);
static
void
isdn_ppp_mp_receive
(
isdn_net_
dev
*
net_dev
,
isdn_net_local
*
lp
,
static
int
isdn_ppp_mp_init
(
isdn_net_local
*
lp
,
ippp_bundle
*
add_to
);
static
void
isdn_ppp_mp_receive
(
isdn_net_
local
*
lp
,
isdn_net_dev
*
idev
,
struct
sk_buff
*
skb
);
static
void
isdn_ppp_mp_cleanup
(
isdn_net_local
*
lp
);
static
void
isdn_ppp_mp_cleanup
(
isdn_net_local
*
lp
);
static
int
isdn_ppp_bundle
(
struct
ippp_struct
*
,
int
unit
);
#endif
/* CONFIG_ISDN_MPP */
...
...
@@ -100,9 +100,8 @@ isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot
* in this case we bind another lp to the master device
*/
static
void
isdn_ppp_free
(
isdn_net_
local
*
lp
)
isdn_ppp_free
(
isdn_net_
dev
*
idev
)
{
isdn_net_dev
*
idev
=
lp
->
netdev
;
unsigned
long
flags
;
struct
ippp_struct
*
is
;
...
...
@@ -116,9 +115,9 @@ isdn_ppp_free(isdn_net_local * lp)
cli
();
#ifdef CONFIG_ISDN_MPP
spin_lock
(
&
lp
->
net
dev
->
pb
->
lock
);
spin_lock
(
&
i
dev
->
pb
->
lock
);
#endif
isdn_net_rm_from_bundle
(
lp
);
isdn_net_rm_from_bundle
(
idev
);
#ifdef CONFIG_ISDN_MPP
if
(
lp
->
netdev
->
pb
->
ref_ct
==
1
)
/* last link in queue? */
isdn_ppp_mp_cleanup
(
lp
);
...
...
@@ -139,7 +138,7 @@ isdn_ppp_free(isdn_net_local * lp)
is
->
state
=
IPPP_OPEN
;
/* fallback to 'OPEN but not ASSIGNED' state */
if
(
is
->
debug
&
0x1
)
printk
(
KERN_DEBUG
"isdn_ppp_free %d %p
%p
\n
"
,
idev
->
ppp_slot
,
lp
,
is
->
idev
);
printk
(
KERN_DEBUG
"isdn_ppp_free %d %p
\n
"
,
idev
->
ppp_slot
,
is
->
idev
);
is
->
idev
=
NULL
;
/* link is down .. set lp to NULL */
idev
->
ppp_slot
=
-
1
;
/* is this OK ?? */
...
...
@@ -152,9 +151,8 @@ isdn_ppp_free(isdn_net_local * lp)
* bind isdn_net_local <=> ippp-device
*/
int
isdn_ppp_bind
(
isdn_net_
local
*
lp
)
isdn_ppp_bind
(
isdn_net_
dev
*
idev
)
{
isdn_net_dev
*
idev
=
lp
->
netdev
;
int
i
;
int
unit
=
0
;
long
flags
;
...
...
@@ -226,10 +224,8 @@ isdn_ppp_bind(isdn_net_local * lp)
*/
static
void
isdn_ppp_wakeup_daemon
(
isdn_net_
local
*
lp
)
isdn_ppp_wakeup_daemon
(
isdn_net_
dev
*
idev
)
{
isdn_net_dev
*
idev
=
lp
->
netdev
;
if
(
idev
->
ppp_slot
<
0
||
idev
->
ppp_slot
>=
ISDN_MAX_CHANNELS
)
{
printk
(
KERN_ERR
"%s: ppp_slot(%d) out of range
\n
"
,
__FUNCTION__
,
idev
->
ppp_slot
);
...
...
@@ -314,8 +310,6 @@ isdn_ppp_open(struct inode *ino, struct file *file)
is
->
maxcid
=
16
;
/* VJ: maxcid */
is
->
tk
=
current
;
init_waitqueue_head
(
&
is
->
wq
);
is
->
first
=
is
->
rq
+
NUM_RCV_BUFFS
-
1
;
/* receive queue */
is
->
last
=
is
->
rq
;
is
->
minor
=
minor
;
#ifdef CONFIG_ISDN_PPP_VJ
/*
...
...
@@ -337,7 +331,6 @@ static int
isdn_ppp_release
(
struct
inode
*
ino
,
struct
file
*
file
)
{
uint
minor
=
minor
(
ino
->
i_rdev
)
-
ISDN_MINOR_PPP
;
int
i
;
struct
ippp_struct
*
is
;
lock_kernel
();
...
...
@@ -356,14 +349,7 @@ isdn_ppp_release(struct inode *ino, struct file *file)
is
->
state
&=
~
IPPP_CONNECT
;
isdn_net_hangup
(
is
->
idev
);
}
for
(
i
=
0
;
i
<
NUM_RCV_BUFFS
;
i
++
)
{
if
(
is
->
rq
[
i
].
buf
)
{
kfree
(
is
->
rq
[
i
].
buf
);
is
->
rq
[
i
].
buf
=
NULL
;
}
}
is
->
first
=
is
->
rq
+
NUM_RCV_BUFFS
-
1
;
/* receive queue */
is
->
last
=
is
->
rq
;
skb_queue_purge
(
&
is
->
rq
);
#ifdef CONFIG_ISDN_PPP_VJ
/* TODO: if this was the previous master: link the slcomp to the new master */
...
...
@@ -487,7 +473,7 @@ isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned
if
(
val
&
SC_ENABLE_IP
&&
!
(
is
->
pppcfg
&
SC_ENABLE_IP
)
&&
(
is
->
state
&
IPPP_CONNECT
))
{
if
(
idev
)
{
/* OK .. we are ready to send buffers */
netif_wake_queue
(
&
idev
->
dev
);
isdn_net_dev_wake_queue
(
i
dev
);
}
}
is
->
pppcfg
=
val
;
...
...
@@ -562,14 +548,16 @@ isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned
return
isdn_ppp_set_compressor
(
is
,
&
data
);
case
PPPIOCGCALLINFO
:
{
isdn_net_local
*
mlp
;
struct
isdn_net_phone
*
phone
;
struct
pppcallinfo
pci
;
int
i
;
memset
((
char
*
)
&
pci
,
0
,
sizeof
(
struct
pppcallinfo
));
if
(
idev
)
{
strncpy
(
pci
.
local_num
,
idev
->
local
.
msn
,
63
);
mlp
=
idev
->
mlp
;
strncpy
(
pci
.
local_num
,
mlp
->
msn
,
63
);
i
=
0
;
list_for_each_entry
(
phone
,
&
idev
->
local
.
phone
[
1
],
list
)
{
list_for_each_entry
(
phone
,
&
mlp
->
phone
[
1
],
list
)
{
if
(
i
++
==
idev
->
dial
)
{
strncpy
(
pci
.
remote_num
,
phone
->
num
,
63
);
break
;
...
...
@@ -580,7 +568,7 @@ isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned
pci
.
calltype
=
CALLTYPE_OUTGOING
;
else
pci
.
calltype
=
CALLTYPE_INCOMING
;
if
(
idev
->
local
.
flags
&
ISDN_NET_CALLBACK
)
if
(
mlp
->
flags
&
ISDN_NET_CALLBACK
)
pci
.
calltype
|=
CALLTYPE_CALLBACK
;
}
return
set_arg
((
void
*
)
arg
,
&
pci
,
sizeof
(
struct
pppcallinfo
));
...
...
@@ -595,12 +583,8 @@ static unsigned int
isdn_ppp_poll
(
struct
file
*
file
,
poll_table
*
wait
)
{
unsigned
int
mask
;
struct
ippp_buf_queue
*
bf
;
struct
ippp_buf_queue
*
bl
;
unsigned
long
flags
;
struct
ippp_struct
*
is
;
lock_kernel
();
is
=
file
->
private_data
;
if
(
is
->
debug
&
0x2
)
...
...
@@ -622,21 +606,15 @@ isdn_ppp_poll(struct file *file, poll_table * wait)
/* we're always ready to send .. */
mask
=
POLLOUT
|
POLLWRNORM
;
save_flags
(
flags
);
cli
();
bl
=
is
->
last
;
bf
=
is
->
first
;
/*
* if IPPP_NOBLOCK is set we return even if we have nothing to read
*/
if
(
bf
->
next
!=
bl
||
(
is
->
state
&
IPPP_NOBLOCK
)
)
{
if
(
!
skb_queue_empty
(
&
is
->
rq
)
||
is
->
state
&
IPPP_NOBLOCK
)
{
is
->
state
&=
~
IPPP_NOBLOCK
;
mask
|=
POLLIN
|
POLLRDNORM
;
}
restore_flags
(
flags
);
out:
unlock_kernel
();
return
mask
;
}
...
...
@@ -647,10 +625,8 @@ isdn_ppp_poll(struct file *file, poll_table * wait)
static
int
isdn_ppp_fill_rq
(
unsigned
char
*
buf
,
int
len
,
int
proto
,
int
slot
)
{
struct
ippp_buf_queue
*
bf
,
*
bl
;
unsigned
long
flags
;
unsigned
char
*
nbuf
;
struct
sk_buff
*
skb
;
unsigned
char
*
p
;
struct
ippp_struct
*
is
;
if
(
slot
<
0
||
slot
>=
ISDN_MAX_CHANNELS
)
{
...
...
@@ -663,35 +639,22 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
printk
(
KERN_DEBUG
"ippp: device not activated.
\n
"
);
return
0
;
}
nbuf
=
(
unsigned
char
*
)
kmalloc
(
len
+
4
,
GFP_ATOMIC
);
if
(
!
nbuf
)
{
printk
(
KERN_WARNING
"ippp: Can't alloc buf
\n
"
);
if
(
skb_queue_len
(
&
is
->
rq
)
>
IPPP_MAX_RQ_LEN
)
{
printk
(
KERN_WARNING
"ippp: Queue is full
\n
"
);
return
0
;
}
nbuf
[
0
]
=
PPP_ALLSTATIONS
;
nbuf
[
1
]
=
PPP_UI
;
nbuf
[
2
]
=
proto
>>
8
;
nbuf
[
3
]
=
proto
&
0xff
;
memcpy
(
nbuf
+
4
,
buf
,
len
);
save_flags
(
flags
);
cli
();
bf
=
is
->
first
;
bl
=
is
->
last
;
if
(
bf
==
bl
)
{
printk
(
KERN_WARNING
"ippp: Queue is full; discarding first buffer
\n
"
);
bf
=
bf
->
next
;
kfree
(
bf
->
buf
);
is
->
first
=
bf
;
skb
=
dev_alloc_skb
(
len
+
4
);
if
(
!
skb
)
{
printk
(
KERN_WARNING
"ippp: Can't alloc buf
\n
"
);
return
0
;
}
bl
->
buf
=
(
char
*
)
nbuf
;
bl
->
len
=
len
+
4
;
is
->
last
=
bl
->
next
;
restore_flags
(
flags
);
p
=
skb_put
(
skb
,
4
)
;
p
+=
put_u8
(
p
,
PPP_ALLSTATIONS
)
;
p
+=
put_u8
(
p
,
PPP_UI
);
p
+=
put_u16
(
p
,
proto
)
;
memcpy
(
skb_put
(
skb
,
len
),
buf
,
len
);
skb_queue_tail
(
&
is
->
rq
,
skb
);
wake_up_interruptible
(
&
is
->
wq
);
return
len
;
...
...
@@ -706,54 +669,36 @@ static ssize_t
isdn_ppp_read
(
struct
file
*
file
,
char
*
buf
,
size_t
count
,
loff_t
*
off
)
{
struct
ippp_struct
*
is
;
struct
ippp_buf_queue
*
b
;
unsigned
long
flags
;
unsigned
char
*
save_buf
;
struct
sk_buff
*
skb
;
int
retval
;
if
(
off
!=
&
file
->
f_pos
)
return
-
ESPIPE
;
lock_kernel
();
is
=
file
->
private_data
;
if
(
!
(
is
->
state
&
IPPP_OPEN
))
{
retval
=
0
;
goto
out
;
}
retval
=
verify_area
(
VERIFY_WRITE
,
(
void
*
)
buf
,
count
);
if
(
retval
)
goto
out
;
save_flags
(
flags
);
cli
();
b
=
is
->
first
->
next
;
save_buf
=
b
->
buf
;
if
(
!
save_buf
)
{
restore_flags
(
flags
);
skb
=
skb_dequeue
(
&
is
->
rq
);
if
(
!
skb
)
{
retval
=
-
EAGAIN
;
goto
out
;
}
if
(
b
->
len
<
count
)
count
=
b
->
len
;
b
->
buf
=
NULL
;
is
->
first
=
b
;
restore_flags
(
flags
);
if
(
copy_to_user
(
buf
,
save_buf
,
count
))
{
kfree
(
save_buf
);
if
(
skb
->
len
>
count
)
{
retval
=
-
EMSGSIZE
;
goto
out_free
;
}
if
(
copy_to_user
(
buf
,
skb
->
data
,
skb
->
len
))
{
retval
=
-
EFAULT
;
goto
out
;
goto
out
_free
;
}
kfree
(
save_buf
);
retval
=
count
;
retval
=
skb
->
len
;
out_free:
dev_kfree_skb
(
skb
);
out:
unlock_kernel
();
return
retval
;
}
...
...
@@ -832,9 +777,9 @@ isdn_ppp_write(struct file *file, const char *buf, size_t count, loff_t *off)
isdn_ppp_frame_log
(
"xmit"
,
skb
->
data
,
skb
->
len
,
32
,
is
->
unit
,
idev
->
ppp_slot
);
}
isdn_ppp_send_ccp
(
idev
,
&
idev
->
local
,
skb
);
/* keeps CCP/compression states in sync */
isdn_ppp_send_ccp
(
idev
,
idev
->
mlp
,
skb
);
/* keeps CCP/compression states in sync */
isdn_net_write_super
(
&
idev
->
local
,
skb
);
isdn_net_write_super
(
idev
,
skb
);
}
}
retval
=
count
;
...
...
@@ -881,15 +826,7 @@ isdn_ppp_init(void)
}
memset
((
char
*
)
ippp_table
[
i
],
0
,
sizeof
(
struct
ippp_struct
));
ippp_table
[
i
]
->
state
=
0
;
ippp_table
[
i
]
->
first
=
ippp_table
[
i
]
->
rq
+
NUM_RCV_BUFFS
-
1
;
ippp_table
[
i
]
->
last
=
ippp_table
[
i
]
->
rq
;
for
(
j
=
0
;
j
<
NUM_RCV_BUFFS
;
j
++
)
{
ippp_table
[
i
]
->
rq
[
j
].
buf
=
NULL
;
ippp_table
[
i
]
->
rq
[
j
].
last
=
ippp_table
[
i
]
->
rq
+
(
NUM_RCV_BUFFS
+
j
-
1
)
%
NUM_RCV_BUFFS
;
ippp_table
[
i
]
->
rq
[
j
].
next
=
ippp_table
[
i
]
->
rq
+
(
j
+
1
)
%
NUM_RCV_BUFFS
;
}
skb_queue_head_init
(
&
ippp_table
[
i
]
->
rq
);
}
return
0
;
}
...
...
@@ -963,10 +900,9 @@ static int isdn_ppp_strip_proto(struct sk_buff *skb)
/*
* handler for incoming packets on a syncPPP interface
*/
static
void
isdn_ppp_receive
(
isdn_net_
dev
*
net_dev
,
isdn_net_local
*
lp
,
static
void
isdn_ppp_receive
(
isdn_net_
local
*
lp
,
isdn_net_dev
*
idev
,
struct
sk_buff
*
skb
)
{
isdn_net_dev
*
idev
=
lp
->
netdev
;
struct
ippp_struct
*
is
;
int
slot
;
int
proto
;
...
...
@@ -976,7 +912,7 @@ static void isdn_ppp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
* huptimer on LCP packets.
*/
if
(
PPP_PROTOCOL
(
skb
->
data
)
!=
PPP_LCP
)
i
sdn_net_reset_huptimer
(
net_dev
,
lp
->
netdev
)
;
i
dev
->
huptimer
=
0
;
slot
=
idev
->
ppp_slot
;
if
(
slot
<
0
||
slot
>
ISDN_MAX_CHANNELS
)
{
...
...
@@ -1012,12 +948,12 @@ static void isdn_ppp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
if
(
!
(
is
->
mpppcfg
&
SC_REJ_MP_PROT
))
{
// we agreed to receive MPPP
if
(
proto
==
PPP_MP
)
{
isdn_ppp_mp_receive
(
net_dev
,
lp
,
skb
);
isdn_ppp_mp_receive
(
lp
,
idev
,
skb
);
return
;
}
}
#endif
isdn_ppp_push_higher
(
net_dev
,
lp
,
skb
,
proto
);
isdn_ppp_push_higher
(
lp
,
idev
,
skb
,
proto
);
}
/*
...
...
@@ -1026,10 +962,10 @@ static void isdn_ppp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
* note: net_dev has to be master net_dev
*/
static
void
isdn_ppp_push_higher
(
isdn_net_dev
*
net_dev
,
isdn_net_local
*
lp
,
struct
sk_buff
*
skb
,
int
proto
)
isdn_ppp_push_higher
(
isdn_net_local
*
lp
,
isdn_net_dev
*
idev
,
struct
sk_buff
*
skb
,
int
proto
)
{
isdn_net_dev
*
idev
=
lp
->
netdev
;
struct
net_device
*
dev
=
&
net_dev
->
dev
;
struct
net_device
*
dev
=
&
lp
->
dev
;
struct
ippp_struct
*
is
,
*
mis
;
int
slot
;
...
...
@@ -1041,14 +977,6 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
}
is
=
ippp_table
[
slot
];
if
(
lp
->
master
)
{
// FIXME?
slot
=
((
isdn_net_local
*
)
(
lp
->
master
->
priv
))
->
netdev
->
ppp_slot
;
if
(
slot
<
0
||
slot
>
ISDN_MAX_CHANNELS
)
{
printk
(
KERN_ERR
"isdn_ppp_push_higher: master->ppp_slot(%d)
\n
"
,
slot
);
goto
drop_packet
;
}
}
mis
=
ippp_table
[
slot
];
if
(
is
->
debug
&
0x10
)
{
...
...
@@ -1079,12 +1007,12 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
case
PPP_VJC_UNCOMP
:
if
(
is
->
debug
&
0x20
)
printk
(
KERN_DEBUG
"isdn_ppp: VJC_UNCOMP
\n
"
);
if
(
net_
dev
->
ppp_slot
<
0
)
{
if
(
i
dev
->
ppp_slot
<
0
)
{
printk
(
KERN_ERR
"%s: net_dev->ppp_slot(%d) out of range
\n
"
,
__FUNCTION__
,
net_
dev
->
ppp_slot
);
__FUNCTION__
,
i
dev
->
ppp_slot
);
goto
drop_packet
;
}
if
(
slhc_remember
(
ippp_table
[
net_
dev
->
ppp_slot
]
->
slcomp
,
skb
->
data
,
skb
->
len
)
<=
0
)
{
if
(
slhc_remember
(
ippp_table
[
i
dev
->
ppp_slot
]
->
slcomp
,
skb
->
data
,
skb
->
len
)
<=
0
)
{
printk
(
KERN_WARNING
"isdn_ppp: received illegal VJC_UNCOMP frame!
\n
"
);
goto
drop_packet
;
}
...
...
@@ -1105,12 +1033,12 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
}
skb_put
(
skb
,
skb_old
->
len
+
128
);
memcpy
(
skb
->
data
,
skb_old
->
data
,
skb_old
->
len
);
if
(
net_
dev
->
ppp_slot
<
0
)
{
if
(
i
dev
->
ppp_slot
<
0
)
{
printk
(
KERN_ERR
"%s: net_dev->ppp_slot(%d) out of range
\n
"
,
__FUNCTION__
,
net_
dev
->
ppp_slot
);
__FUNCTION__
,
i
dev
->
ppp_slot
);
goto
drop_packet
;
}
pkt_len
=
slhc_uncompress
(
ippp_table
[
net_
dev
->
ppp_slot
]
->
slcomp
,
pkt_len
=
slhc_uncompress
(
ippp_table
[
i
dev
->
ppp_slot
]
->
slcomp
,
skb
->
data
,
skb_old
->
len
);
kfree_skb
(
skb_old
);
if
(
pkt_len
<
0
)
...
...
@@ -1123,7 +1051,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
#endif
case
PPP_CCP
:
case
PPP_CCPFRAG
:
isdn_ppp_receive_ccp
(
net_
dev
,
lp
,
skb
,
proto
);
isdn_ppp_receive_ccp
(
i
dev
,
lp
,
skb
,
proto
);
/* Dont pop up ResetReq/Ack stuff to the daemon any
longer - the job is done already */
if
(
skb
->
data
[
0
]
==
CCP_RESETREQ
||
...
...
@@ -1146,7 +1074,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
return
;
drop_packet:
net_dev
->
local
.
stats
.
rx_dropped
++
;
lp
->
stats
.
rx_dropped
++
;
kfree_skb
(
skb
);
}
...
...
@@ -1184,20 +1112,21 @@ static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p,int len)
* skb isn't allowed!!
*/
int
isdn_ppp_
xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
net
dev
)
static
int
isdn_ppp_
start_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
n
dev
)
{
isdn_net_local
*
lp
,
*
mlp
;
isdn_net_dev
*
idev
;
isdn_net_dev
*
nd
;
isdn_net_local
*
mlp
=
ndev
->
priv
;
isdn_net_dev
*
idev
=
list_entry
(
mlp
->
online
.
next
,
isdn_net_dev
,
online
);
unsigned
int
proto
=
PPP_IP
;
/* 0x21 */
struct
ippp_struct
*
ipt
,
*
ipts
;
int
slot
;
mlp
=
(
isdn_net_local
*
)
(
netdev
->
priv
);
nd
=
mlp
->
netdev
;
/* get master lp */
ndev
->
trans_start
=
jiffies
;
slot
=
nd
->
ppp_slot
;
if
(
list_empty
(
&
mlp
->
online
))
return
isdn_net_autodial
(
skb
,
ndev
);
slot
=
idev
->
ppp_slot
;
if
(
slot
<
0
||
slot
>
ISDN_MAX_CHANNELS
)
{
printk
(
KERN_ERR
"isdn_ppp_xmit: lp->ppp_slot(%d)
\n
"
,
slot
);
...
...
@@ -1208,7 +1137,8 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
if
(
!
(
ipts
->
pppcfg
&
SC_ENABLE_IP
))
{
/* PPP connected ? */
if
(
ipts
->
debug
&
0x1
)
printk
(
KERN_INFO
"%s: IP frame delayed.
\n
"
,
netdev
->
name
);
printk
(
KERN_INFO
"%s: IP frame delayed.
\n
"
,
ndev
->
name
);
netif_stop_queue
(
ndev
);
return
1
;
}
...
...
@@ -1226,13 +1156,13 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
return
0
;
}
lp
=
isdn_net_get_locked_lp
(
nd
);
if
(
!
lp
)
{
printk
(
KERN_WARNING
"%s: all channels busy - requeuing!
\n
"
,
netdev
->
name
);
idev
=
isdn_net_get_locked_dev
(
mlp
);
if
(
!
idev
)
{
printk
(
KERN_WARNING
"%s: all channels busy - requeuing!
\n
"
,
ndev
->
name
);
netif_stop_queue
(
ndev
);
return
1
;
}
/* we have our lp locked from now on */
idev
=
lp
->
netdev
;
slot
=
idev
->
ppp_slot
;
if
(
slot
<
0
||
slot
>
ISDN_MAX_CHANNELS
)
{
printk
(
KERN_ERR
"isdn_ppp_xmit: lp->ppp_slot(%d)
\n
"
,
...
...
@@ -1385,10 +1315,10 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
isdn_ppp_frame_log
(
"xmit"
,
skb
->
data
,
skb
->
len
,
32
,
ipt
->
unit
,
idev
->
ppp_slot
);
}
isdn_net_writebuf_skb
(
lp
,
skb
);
isdn_net_writebuf_skb
(
idev
,
skb
);
unlock:
spin_unlock_bh
(
&
lp
->
xmit_lock
);
spin_unlock_bh
(
&
idev
->
xmit_lock
);
return
0
;
}
...
...
@@ -1459,7 +1389,7 @@ static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to )
is
->
mp_seqno
=
0
;
if
((
lp
->
netdev
->
pb
=
isdn_ppp_mp_bundle_alloc
())
==
NULL
)
return
-
ENOMEM
;
lp
->
next
=
lp
->
last
=
lp
;
/* nobody else in a queue */
lp
->
netdev
->
pb
->
frags
=
NULL
;
lp
->
netdev
->
pb
->
frames
=
0
;
lp
->
netdev
->
pb
->
seq
=
LONG_MAX
;
...
...
@@ -1479,12 +1409,12 @@ static void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
static
void
isdn_ppp_mp_free_skb
(
ippp_bundle
*
mp
,
struct
sk_buff
*
skb
);
static
void
isdn_ppp_mp_print_recv_pkt
(
int
slot
,
struct
sk_buff
*
skb
);
static
void
isdn_ppp_mp_receive
(
isdn_net_
dev
*
net_dev
,
isdn_net_local
*
lp
,
static
void
isdn_ppp_mp_receive
(
isdn_net_
local
*
lp
,
isdn_net_dev
*
dev
,
struct
sk_buff
*
skb
)
{
isdn_net_dev
*
idev
=
lp
->
netdev
;
struct
ippp_struct
*
is
;
isdn_net_
local
*
lpq
;
isdn_net_
dev
*
qdev
;
ippp_bundle
*
mp
;
isdn_mppp_stats
*
stats
;
struct
sk_buff
*
newfrag
,
*
frag
,
*
start
,
*
nextf
;
...
...
@@ -1492,8 +1422,8 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
unsigned
long
flags
;
int
slot
;
spin_lock_irqsave
(
&
net_
dev
->
pb
->
lock
,
flags
);
mp
=
net_
dev
->
pb
;
spin_lock_irqsave
(
&
lp
->
net
dev
->
pb
->
lock
,
flags
);
mp
=
lp
->
net
dev
->
pb
;
stats
=
&
mp
->
stats
;
slot
=
idev
->
ppp_slot
;
if
(
slot
<
0
||
slot
>
ISDN_MAX_CHANNELS
)
{
...
...
@@ -1531,8 +1461,8 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
/* find the minimum received sequence number over all links */
is
->
last_link_seqno
=
minseq
=
newseq
;
for
(
lpq
=
net_dev
->
queue
;;
)
{
slot
=
lpq
->
net
dev
->
ppp_slot
;
list_for_each_entry
(
qdev
,
&
lp
->
online
,
online
)
{
slot
=
q
dev
->
ppp_slot
;
if
(
slot
<
0
||
slot
>
ISDN_MAX_CHANNELS
)
{
printk
(
KERN_ERR
"%s: lpq->ppp_slot(%d)
\n
"
,
__FUNCTION__
,
slot
);
...
...
@@ -1541,8 +1471,6 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
if
(
MP_LT
(
lls
,
minseq
))
minseq
=
lls
;
}
if
((
lpq
=
lpq
->
next
)
==
net_dev
->
queue
)
break
;
}
if
(
MP_LT
(
minseq
,
mp
->
seq
))
minseq
=
mp
->
seq
;
/* can't go beyond already processed
...
...
@@ -1631,7 +1559,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
if
(
start
!=
NULL
&&
(
MP_FLAGS
(
frag
)
&
MP_END_FRAG
))
{
minseq
=
mp
->
seq
=
(
thisseq
+
1
)
&
MP_LONGSEQ_MASK
;
/* Reassemble the packet then dispatch it */
isdn_ppp_mp_reassembly
(
net_
dev
,
lp
,
start
,
nextf
);
isdn_ppp_mp_reassembly
(
lp
->
net
dev
,
lp
,
start
,
nextf
);
start
=
NULL
;
frag
=
NULL
;
...
...
@@ -1808,7 +1736,7 @@ void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
}
}
proto
=
isdn_ppp_strip_proto
(
skb
);
isdn_ppp_push_higher
(
net_dev
,
lp
,
skb
,
proto
);
isdn_ppp_push_higher
(
lp
,
idev
,
skb
,
proto
);
}
static
void
isdn_ppp_mp_free_skb
(
ippp_bundle
*
mp
,
struct
sk_buff
*
skb
)
...
...
@@ -1844,7 +1772,7 @@ isdn_ppp_bundle(struct ippp_struct *is, int unit)
spin_lock_irqsave
(
&
p
->
pb
->
lock
,
flags
);
nidev
=
is
->
idev
;
idev
=
p
->
queue
->
netdev
;
idev
=
list_entry
(
p
->
mlp
->
online
.
next
,
isdn_net_dev
,
online
)
;
if
(
nidev
->
ppp_slot
<
0
||
nidev
->
ppp_slot
>=
ISDN_MAX_CHANNELS
||
idev
->
ppp_slot
<
0
||
idev
->
ppp_slot
>=
ISDN_MAX_CHANNELS
)
{
printk
(
KERN_ERR
"ippp_bundle: binding to invalid slot %d
\n
"
,
...
...
@@ -1854,7 +1782,7 @@ isdn_ppp_bundle(struct ippp_struct *is, int unit)
goto
out
;
}
isdn_net_add_to_bundle
(
p
,
&
nidev
->
local
);
isdn_net_add_to_bundle
(
p
->
mlp
,
nidev
);
ippp_table
[
nidev
->
ppp_slot
]
->
unit
=
ippp_table
[
idev
->
ppp_slot
]
->
unit
;
...
...
@@ -1863,7 +1791,7 @@ isdn_ppp_bundle(struct ippp_struct *is, int unit)
(
SC_ENABLE_IP
|
SC_NO_TCP_CCID
|
SC_REJ_COMP_TCP
);
ippp_table
[
nidev
->
ppp_slot
]
->
mpppcfg
|=
ippp_table
[
idev
->
ppp_slot
]
->
mpppcfg
&
(
SC_MP_PROT
|
SC_REJ_MP_PROT
|
SC_OUT_SHORT_SEQ
|
SC_IN_SHORT_SEQ
);
rc
=
isdn_ppp_mp_init
(
&
nidev
->
local
,
p
->
pb
);
rc
=
isdn_ppp_mp_init
(
nidev
->
mlp
,
p
->
pb
);
out:
spin_unlock_irqrestore
(
&
p
->
pb
->
lock
,
flags
);
return
rc
;
...
...
@@ -1936,7 +1864,7 @@ isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if
(
copy_to_user
(
r
,
PPP_VERSION
,
len
))
error
=
-
EFAULT
;
break
;
case
SIOCGPPPSTATS
:
error
=
isdn_ppp_dev_ioctl_stats
(
lp
->
netdev
->
ppp_slot
,
ifr
,
dev
);
error
=
isdn_ppp_dev_ioctl_stats
(
0
,
ifr
,
dev
);
break
;
default:
error
=
-
EINVAL
;
...
...
@@ -1977,28 +1905,25 @@ isdn_ppp_dial_slave(char *name)
{
#ifdef CONFIG_ISDN_MPP
isdn_net_dev
*
idev
;
isdn_net_local
*
lp
;
struct
net_device
*
sdev
;
isdn_net_dev
*
sdev
;
idev
=
isdn_net_findif
(
name
);
if
(
!
idev
)
return
1
;
lp
=
&
idev
->
local
;
if
(
!
isdn_net_bound
(
idev
))
return
5
;
sdev
=
lp
->
slave
;
sdev
=
idev
->
slave
;
while
(
sdev
)
{
isdn_net_local
*
mlp
=
(
isdn_net_local
*
)
sdev
->
priv
;
if
(
!
isdn_net_bound
(
mlp
->
netdev
))
if
(
!
isdn_net_bound
(
sdev
))
break
;
sdev
=
mlp
->
slave
;
sdev
=
sdev
->
slave
;
}
if
(
!
sdev
)
return
2
;
isdn_net_dial_req
(
(
isdn_net_local
*
)
sdev
->
pri
v
);
isdn_net_dial_req
(
sde
v
);
return
0
;
#else
return
-
1
;
...
...
@@ -2009,35 +1934,20 @@ int
isdn_ppp_hangup_slave
(
char
*
name
)
{
#ifdef CONFIG_ISDN_MPP
isdn_net_dev
*
idev
;
isdn_net_local
*
lp
,
*
mlp
=
NULL
;
struct
net_device
*
sdev
;
isdn_net_dev
*
idev
,
*
sdev
;
idev
=
isdn_net_findif
(
name
);
if
(
!
idev
)
return
1
;
lp
=
&
idev
->
local
;
if
(
!
isdn_net_bound
(
idev
))
return
5
;
sdev
=
lp
->
slave
;
while
(
sdev
)
{
mlp
=
(
isdn_net_local
*
)
sdev
->
priv
;
if
(
mlp
->
slave
)
{
/* find last connected link in chain */
isdn_net_local
*
nlp
=
(
isdn_net_local
*
)
mlp
->
slave
->
priv
;
if
(
!
isdn_net_bound
(
nlp
->
netdev
))
break
;
}
else
if
(
isdn_net_bound
(
mlp
->
netdev
))
break
;
sdev
=
mlp
->
slave
;
}
if
(
!
sdev
)
sdev
=
idev
->
slave
;
if
(
!
sdev
||
!
isdn_net_bound
(
sdev
))
return
2
;
isdn_net_hangup
(
mlp
->
net
dev
);
isdn_net_hangup
(
s
dev
);
return
0
;
#else
return
-
1
;
...
...
@@ -2139,7 +2049,7 @@ static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
printk
(
KERN_DEBUG
"Sending CCP Frame:
\n
"
);
isdn_ppp_frame_log
(
"ccp-xmit"
,
skb
->
data
,
skb
->
len
,
32
,
is
->
unit
,
idev
->
ppp_slot
);
isdn_net_write_super
(
&
idev
->
local
,
skb
);
isdn_net_write_super
(
idev
,
skb
);
}
/* Allocate the reset state vector */
...
...
@@ -2537,10 +2447,9 @@ static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
* we received a CCP frame ..
* not a clean solution, but we MUST handle a few cases in the kernel
*/
static
void
isdn_ppp_receive_ccp
(
isdn_net_dev
*
net_
dev
,
isdn_net_local
*
lp
,
static
void
isdn_ppp_receive_ccp
(
isdn_net_dev
*
i
dev
,
isdn_net_local
*
lp
,
struct
sk_buff
*
skb
,
int
proto
)
{
isdn_net_dev
*
idev
=
lp
->
netdev
;
struct
ippp_struct
*
is
;
struct
ippp_struct
*
mis
;
int
len
;
...
...
@@ -2557,15 +2466,6 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
is
=
ippp_table
[
idev
->
ppp_slot
];
isdn_ppp_frame_log
(
"ccp-rcv"
,
skb
->
data
,
skb
->
len
,
32
,
is
->
unit
,
idev
->
ppp_slot
);
if
(
lp
->
master
)
{
int
slot
=
((
isdn_net_local
*
)
(
lp
->
master
->
priv
))
->
netdev
->
ppp_slot
;
if
(
slot
<
0
||
slot
>
ISDN_MAX_CHANNELS
)
{
printk
(
KERN_ERR
"%s: slot(%d) out of range
\n
"
,
__FUNCTION__
,
slot
);
return
;
}
mis
=
ippp_table
[
slot
];
}
else
mis
=
is
;
switch
(
skb
->
data
[
0
])
{
...
...
@@ -2715,9 +2615,8 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
* and I tried to modify this file according to that. --abp
*/
static
void
isdn_ppp_send_ccp
(
isdn_net_dev
*
net_
dev
,
isdn_net_local
*
lp
,
struct
sk_buff
*
skb
)
static
void
isdn_ppp_send_ccp
(
isdn_net_dev
*
i
dev
,
isdn_net_local
*
lp
,
struct
sk_buff
*
skb
)
{
isdn_net_dev
*
idev
=
lp
->
netdev
;
struct
ippp_struct
*
mis
,
*
is
;
int
proto
,
slot
=
idev
->
ppp_slot
;
unsigned
char
*
data
;
...
...
@@ -2745,15 +2644,6 @@ static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct
printk
(
KERN_DEBUG
"Received CCP frame from daemon:
\n
"
);
isdn_ppp_frame_log
(
"ccp-xmit"
,
skb
->
data
,
skb
->
len
,
32
,
is
->
unit
,
idev
->
ppp_slot
);
if
(
lp
->
master
)
{
slot
=
((
isdn_net_local
*
)
(
lp
->
master
->
priv
))
->
netdev
->
ppp_slot
;
if
(
slot
<
0
||
slot
>
ISDN_MAX_CHANNELS
)
{
printk
(
KERN_ERR
"%s: slot(%d) out of range
\n
"
,
__FUNCTION__
,
slot
);
return
;
}
mis
=
ippp_table
[
slot
];
}
else
mis
=
is
;
if
(
mis
!=
is
)
printk
(
KERN_DEBUG
"isdn_ppp: Ouch! Master CCP sends on slave slot!
\n
"
);
...
...
@@ -2926,6 +2816,7 @@ isdn_ppp_header(struct sk_buff *skb, struct net_device *dev,
}
struct
isdn_netif_ops
isdn_ppp_ops
=
{
.
hard_start_xmit
=
isdn_ppp_start_xmit
,
.
hard_header
=
isdn_ppp_header
,
.
do_ioctl
=
isdn_ppp_dev_ioctl
,
.
flags
=
IFF_NOARP
|
IFF_POINTOPOINT
,
...
...
drivers/isdn/i4l/isdn_ppp.h
View file @
994b6e06
...
...
@@ -20,20 +20,6 @@ extern void isdn_ppp_cleanup(void);
extern
int
isdn_ppp_dial_slave
(
char
*
);
extern
int
isdn_ppp_hangup_slave
(
char
*
);
#ifdef CONFIG_ISDN_PPP
int
isdn_ppp_xmit
(
struct
sk_buff
*
,
struct
net_device
*
);
#else
static
inline
int
isdn_ppp_xmit
(
struct
sk_buff
*
,
struct
net_device
*
)
{
return
0
;
}
#endif
#define IPPP_OPEN 0x01
#define IPPP_CONNECT 0x02
#define IPPP_CLOSEWAIT 0x04
...
...
include/linux/isdn.h
View file @
994b6e06
...
...
@@ -16,6 +16,9 @@
#include <linux/ioctl.h>
// FIXME!!!
#include <../drivers/isdn/i4l/isdn_fsm.h>
#ifdef CONFIG_COBALT_MICRO_SERVER
/* Save memory */
#define ISDN_MAX_DRIVERS 2
...
...
@@ -282,6 +285,8 @@ struct isdn_net_dev_s;
struct
isdn_net_local_s
;
struct
isdn_netif_ops
{
int
(
*
hard_start_xmit
)
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
);
int
(
*
hard_header
)
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
,
unsigned
short
type
,
...
...
@@ -294,26 +299,24 @@ struct isdn_netif_ops {
unsigned
short
flags
;
/* interface flags (a la BSD) */
unsigned
short
type
;
/* interface hardware type */
unsigned
char
addr_len
;
/* hardware address length */
void
(
*
receive
)(
struct
isdn_net_
dev_s
*
p
,
struct
isdn_net_
local_s
*
olp
,
struct
sk_buff
*
skb
);
void
(
*
connected
)(
struct
isdn_net_
local_s
*
lp
);
void
(
*
disconnected
)(
struct
isdn_net_
local_s
*
lp
);
int
(
*
bind
)(
struct
isdn_net_
local_s
*
lp
);
void
(
*
unbind
)(
struct
isdn_net_
local_s
*
lp
);
int
(
*
init
)(
struct
isdn_net_local_s
*
lp
);
void
(
*
cleanup
)(
struct
isdn_net_local_s
*
lp
);
int
(
*
open
)(
struct
isdn_net_local_s
*
lp
);
void
(
*
close
)(
struct
isdn_net_local_s
*
lp
);
void
(
*
receive
)(
struct
isdn_net_
local_s
*
,
struct
isdn_net_
dev_s
*
,
struct
sk_buff
*
);
void
(
*
connected
)(
struct
isdn_net_
dev_s
*
);
void
(
*
disconnected
)(
struct
isdn_net_
dev_s
*
);
int
(
*
bind
)(
struct
isdn_net_
dev_s
*
);
void
(
*
unbind
)(
struct
isdn_net_
dev_s
*
);
int
(
*
init
)(
struct
isdn_net_local_s
*
);
void
(
*
cleanup
)(
struct
isdn_net_local_s
*
);
int
(
*
open
)(
struct
isdn_net_local_s
*
);
void
(
*
close
)(
struct
isdn_net_local_s
*
);
};
/* Local interface-data */
typedef
struct
isdn_net_local_s
{
ulong
magic
;
spinlock_t
lock
;
struct
net_device_stats
stats
;
/* Ethernet Statistics */
int
flags
;
/* Connection-flags */
int
dialretry
;
/* Counter for Dialout-retries */
int
dialmax
;
/* Max. Number of Dial-retries */
int
dialtimeout
;
/* How long shall we try on dialing */
int
dialwait
;
/* wait after failed attempt */
...
...
@@ -329,26 +332,17 @@ typedef struct isdn_net_local_s {
u_char
l2_proto
;
/* Layer-2-protocol */
u_char
l3_proto
;
/* Layer-3-protocol */
int
sqfull
;
/* Flag: netdev-queue overloaded */
ulong
sqfull_stamp
;
/* Start-Time of overload */
ulong
slavedelay
;
/* Dynamic bundling delaytime */
int
triggercps
;
/* BogoCPS needed for trigger slave */
struct
list_head
phone
[
2
];
/* List of remote-phonenumbers */
/* phone[0] = Incoming Numbers */
/* phone[1] = Outgoing Numbers */
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 */
struct
isdn_net_local_s
*
last
;
/* Ptr to last link in bundle */
struct
isdn_net_dev_s
*
netdev
;
/* Ptr to netdev */
struct
sk_buff_head
super_tx_queue
;
/* List of supervisory frames to */
/* be transmitted asap */
atomic_t
frame_cnt
;
/* number of frames currently */
/* queued in HL driver */
/* Ptr to orig. hard_header_cache */
spinlock_t
xmit_lock
;
/* used to protect the xmit path of */
/* a particular channel (including */
/* the frame_cnt */
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 */
#ifdef CONFIG_ISDN_X25
struct
concap_device_ops
*
dops
;
/* callbacks used by encapsulator */
...
...
@@ -361,33 +355,34 @@ typedef struct isdn_net_local_s {
ulong
cisco_last_slarp_in
;
/* jiffie of last keepalive packet we received */
char
cisco_line_state
;
/* state of line according to keepalive packets */
char
cisco_debserint
;
/* debugging flag of cisco hdlc with slarp */
struct
timer_list
cisco_timer
;
struct
work_struct
tqueue
;
struct
isdn_netif_ops
*
ops
;
struct
net_device
dev
;
/* interface to upper levels */
}
isdn_net_local
;
/* the interface itself */
typedef
struct
isdn_net_dev_s
{
isdn_net_local
local
;
int
isdn_slot
;
/* Index to isdn device/channel */
int
pre_device
;
/* Preselected isdn-device */
int
pre_channel
;
/* Preselected isdn-channel */
int
exclusive
;
/* -1 if non excl./idx to excl chan */
struct
timer_list
dial_timer
;
/* dial events timer */
struct
fsm_inst
fi
;
/* call control state machine */
int
dial_event
;
/* event in case of timer expiry */
int
dialstate
;
/* State for dialing */
int
dial
;
/* # of phone number just dialed */
int
outgoing
;
/* Flag: outgoing call */
unsigned
long
dialstarted
;
/* first dialing-attempt */
unsigned
long
dialwait_timer
;
/* earliest next dialing-attempt */
int
dialretry
;
/* Counter for Dialout-retries */
int
cps
;
/* current speed of this interface */
int
transcount
;
/* byte-counter for cps-calculation */
int
last_jiffies
;
/* when transcount was reset */
int
sqfull
;
/* Flag: netdev-queue overloaded */
ulong
sqfull_stamp
;
/* Start-Time of overload */
struct
timer_list
hup_timer
;
/* auto hangup timer */
int
huptimer
;
/* Timeout-counter for auto-hangup */
int
charge
;
/* Counter for charging units */
int
charge_state
;
/* ChargeInfo state machine */
...
...
@@ -397,13 +392,22 @@ typedef struct isdn_net_dev_s {
int
pppbind
;
/* ippp device for bindings */
int
ppp_slot
;
/* PPPD device slot number */
isdn_net_local
*
queue
;
/* circular list of all bundled
channels, which are currently
online */
spinlock_t
queue_lock
;
/* lock to protect queue */
spinlock_t
xmit_lock
;
/* used to protect the xmit path of */
/* a particular channel (including */
/* the frame_cnt */
struct
sk_buff_head
super_tx_queue
;
/* List of supervisory frames to */
/* be transmitted asap */
atomic_t
frame_cnt
;
/* number of frames currently */
/* queued in HL driver */
struct
tasklet_struct
tlet
;
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 */
char
name
[
10
];
/* Name of device */
struct
list_head
global_list
;
/* global list of all isdn_net_devs */
struct
net_device
dev
;
/* interface to upper levels */
#ifdef CONFIG_ISDN_PPP
ippp_bundle
*
pb
;
/* pointer to the common bundle structure
* with the per-bundle data */
...
...
include/linux/isdn_ppp.h
View file @
994b6e06
...
...
@@ -159,14 +159,7 @@ typedef struct {
isdn_mppp_stats
stats
;
}
ippp_bundle
;
#define NUM_RCV_BUFFS 64
struct
ippp_buf_queue
{
struct
ippp_buf_queue
*
next
;
struct
ippp_buf_queue
*
last
;
char
*
buf
;
/* NULL here indicates end of queue */
int
len
;
};
#define IPPP_MAX_RQ_LEN 8
/* The data structure for one CCP reset transaction */
enum
ippp_ccp_reset_states
{
...
...
@@ -201,9 +194,7 @@ struct ippp_ccp_reset {
struct
ippp_struct
{
struct
ippp_struct
*
next_link
;
int
state
;
struct
ippp_buf_queue
rq
[
NUM_RCV_BUFFS
];
/* packet queue for isdn_ppp_read() */
struct
ippp_buf_queue
*
first
;
/* pointer to (current) first packet */
struct
ippp_buf_queue
*
last
;
/* pointer to (current) last used packet in queue */
struct
sk_buff_head
rq
;
wait_queue_head_t
wq
;
struct
task_struct
*
tk
;
unsigned
int
mpppcfg
;
...
...
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