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
a4041f6f
Commit
a4041f6f
authored
Sep 19, 2002
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge master.kernel.org:/home/davem/BK/net-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
parents
046e9c3b
1e96b980
Changes
53
Show whitespace changes
Inline
Side-by-side
Showing
53 changed files
with
4239 additions
and
4150 deletions
+4239
-4150
MAINTAINERS
MAINTAINERS
+6
-6
drivers/char/random.c
drivers/char/random.c
+97
-70
drivers/net/tg3.c
drivers/net/tg3.c
+51
-11
drivers/net/tun.c
drivers/net/tun.c
+3
-1
include/net/ax25.h
include/net/ax25.h
+20
-5
include/net/llc_actn.h
include/net/llc_actn.h
+1
-0
include/net/llc_c_ac.h
include/net/llc_c_ac.h
+5
-0
include/net/llc_c_ev.h
include/net/llc_c_ev.h
+9
-0
include/net/llc_main.h
include/net/llc_main.h
+1
-1
net/ax25/Config.in
net/ax25/Config.in
+1
-1
net/ax25/TODO
net/ax25/TODO
+24
-0
net/ax25/af_ax25.c
net/ax25/af_ax25.c
+831
-732
net/ax25/ax25_addr.c
net/ax25/ax25_addr.c
+9
-22
net/ax25/ax25_dev.c
net/ax25/ax25_dev.c
+47
-46
net/ax25/ax25_ds_in.c
net/ax25/ax25_ds_in.c
+201
-214
net/ax25/ax25_ds_subr.c
net/ax25/ax25_ds_subr.c
+21
-28
net/ax25/ax25_ds_timer.c
net/ax25/ax25_ds_timer.c
+75
-80
net/ax25/ax25_iface.c
net/ax25/ax25_iface.c
+58
-66
net/ax25/ax25_in.c
net/ax25/ax25_in.c
+77
-103
net/ax25/ax25_ip.c
net/ax25/ax25_ip.c
+27
-30
net/ax25/ax25_out.c
net/ax25/ax25_out.c
+44
-70
net/ax25/ax25_route.c
net/ax25/ax25_route.c
+246
-185
net/ax25/ax25_std_in.c
net/ax25/ax25_std_in.c
+304
-325
net/ax25/ax25_std_subr.c
net/ax25/ax25_std_subr.c
+6
-20
net/ax25/ax25_std_timer.c
net/ax25/ax25_std_timer.c
+72
-86
net/ax25/ax25_subr.c
net/ax25/ax25_subr.c
+23
-47
net/ax25/ax25_timer.c
net/ax25/ax25_timer.c
+74
-71
net/ax25/ax25_uid.c
net/ax25/ax25_uid.c
+84
-67
net/ax25/sysctl_net_ax25.c
net/ax25/sysctl_net_ax25.c
+11
-6
net/llc/llc_actn.c
net/llc/llc_actn.c
+2
-8
net/llc/llc_c_ac.c
net/llc/llc_c_ac.c
+15
-42
net/llc/llc_c_ev.c
net/llc/llc_c_ev.c
+12
-6
net/llc/llc_main.c
net/llc/llc_main.c
+65
-19
net/llc/llc_sock.c
net/llc/llc_sock.c
+4
-2
net/netrom/af_netrom.c
net/netrom/af_netrom.c
+229
-254
net/netrom/nr_dev.c
net/netrom/nr_dev.c
+6
-18
net/netrom/nr_in.c
net/netrom/nr_in.c
+142
-160
net/netrom/nr_loopback.c
net/netrom/nr_loopback.c
+5
-14
net/netrom/nr_out.c
net/netrom/nr_out.c
+9
-18
net/netrom/nr_route.c
net/netrom/nr_route.c
+129
-151
net/netrom/nr_subr.c
net/netrom/nr_subr.c
+68
-78
net/netrom/nr_timer.c
net/netrom/nr_timer.c
+67
-66
net/netrom/sysctl_net_netrom.c
net/netrom/sysctl_net_netrom.c
+6
-5
net/rose/af_rose.c
net/rose/af_rose.c
+309
-316
net/rose/rose_dev.c
net/rose/rose_dev.c
+6
-14
net/rose/rose_in.c
net/rose/rose_in.c
+150
-165
net/rose/rose_link.c
net/rose/rose_link.c
+24
-32
net/rose/rose_loopback.c
net/rose/rose_loopback.c
+5
-13
net/rose/rose_out.c
net/rose/rose_out.c
+7
-16
net/rose/rose_route.c
net/rose/rose_route.c
+309
-206
net/rose/rose_subr.c
net/rose/rose_subr.c
+183
-192
net/rose/rose_timer.c
net/rose/rose_timer.c
+53
-57
net/rose/sysctl_net_rose.c
net/rose/sysctl_net_rose.c
+6
-5
No files found.
MAINTAINERS
View file @
a4041f6f
...
...
@@ -240,8 +240,8 @@ L: linux-net@vger.kernel.org
S: Maintained
AX.25 NETWORK LAYER
P:
Matthias Welwarsky
M:
dg2fef@afthd.tu-darmstadt.de
P:
Ralf Baechle
M:
ralf@linux-mips.org
L: linux-hams@vger.kernel.org
S: Maintained
...
...
@@ -1113,8 +1113,8 @@ L: netfilter-devel@lists.netfilter.org
S: Supported
NETROM NETWORK LAYER
P:
Tomi Manninen
M:
Tomi.Manninen@hut.fi
P:
Ralf Baechle
M:
ralf@linux-mips.org
L: linux-hams@vger.kernel.org
S: Maintained
...
...
@@ -1363,8 +1363,8 @@ W: http://www.namesys.com
S: Supported
ROSE NETWORK LAYER
P:
Jean-Paul Roubelat
M:
jpr@f6fbb
.org
P:
Ralf Baechle
M:
ralf@linux-mips
.org
L: linux-hams@vger.kernel.org
S: Maintained
...
...
drivers/char/random.c
View file @
a4041f6f
...
...
@@ -2033,57 +2033,103 @@ static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12])
/* This should not be decreased so low that ISNs wrap too fast. */
#define REKEY_INTERVAL 300
/*
* Bit layout of the tcp sequence numbers (before adding current time):
* bit 24-31: increased after every key exchange
* bit 0-23: hash(source,dest)
*
* The implementation is similar to the algorithm described
* in the Appendix of RFC 1185, except that
* - it uses a 1 MHz clock instead of a 250 kHz clock
* - it performs a rekey every 5 minutes, which is equivalent
* to a (source,dest) tulple dependent forward jump of the
* clock by 0..2^(HASH_BITS+1)
*
* Thus the average ISN wraparound time is 68 minutes instead of
* 4.55 hours.
*
* SMP cleanup and lock avoidance with poor man's RCU.
* Manfred Spraul <manfred@colorfullife.com>
*
*/
#define COUNT_BITS 8
#define COUNT_MASK ( (1<<COUNT_BITS)-1)
#define HASH_BITS 24
#define HASH_MASK ( (1<<HASH_BITS)-1 )
static
struct
keydata
{
time_t
rekey_time
;
__u32
count
;
// already shifted to the final position
__u32
secret
[
12
];
}
____cacheline_aligned
ip_keydata
[
2
];
static
spinlock_t
ip_lock
=
SPIN_LOCK_UNLOCKED
;
static
unsigned
int
ip_cnt
;
static
struct
keydata
*
__check_and_rekey
(
time_t
time
)
{
struct
keydata
*
keyptr
;
spin_lock
(
&
ip_lock
);
keyptr
=
&
ip_keydata
[
ip_cnt
&
1
];
if
(
!
keyptr
->
rekey_time
||
(
time
-
keyptr
->
rekey_time
)
>
REKEY_INTERVAL
)
{
keyptr
=
&
ip_keydata
[
1
^
(
ip_cnt
&
1
)];
keyptr
->
rekey_time
=
time
;
get_random_bytes
(
keyptr
->
secret
,
sizeof
(
keyptr
->
secret
));
keyptr
->
count
=
(
ip_cnt
&
COUNT_MASK
)
<<
HASH_BITS
;
mb
();
ip_cnt
++
;
}
spin_unlock
(
&
ip_lock
);
return
keyptr
;
}
static
inline
struct
keydata
*
check_and_rekey
(
time_t
time
)
{
struct
keydata
*
keyptr
=
&
ip_keydata
[
ip_cnt
&
1
];
rmb
();
if
(
!
keyptr
->
rekey_time
||
(
time
-
keyptr
->
rekey_time
)
>
REKEY_INTERVAL
)
{
keyptr
=
__check_and_rekey
(
time
);
}
return
keyptr
;
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
__u32
secure_tcpv6_sequence_number
(
__u32
*
saddr
,
__u32
*
daddr
,
__u16
sport
,
__u16
dport
)
{
static
__u32
rekey_time
;
static
__u32
count
;
static
__u32
secret
[
12
];
struct
timeval
tv
;
__u32
seq
;
__u32
hash
[
12
];
struct
keydata
*
keyptr
;
/* The procedure is the same as for IPv4, but addresses are longer. */
/* The procedure is the same as for IPv4, but addresses are longer.
* Thus we must use twothirdsMD4Transform.
*/
do_gettimeofday
(
&
tv
);
/* We need the usecs below... */
keyptr
=
check_and_rekey
(
tv
.
tv_sec
);
if
(
!
rekey_time
||
(
tv
.
tv_sec
-
rekey_time
)
>
REKEY_INTERVAL
)
{
rekey_time
=
tv
.
tv_sec
;
/* First five words are overwritten below. */
get_random_bytes
(
&
secret
[
5
],
sizeof
(
secret
)
-
5
*
4
);
count
=
(
tv
.
tv_sec
/
REKEY_INTERVAL
)
<<
HASH_BITS
;
}
memcpy
(
secret
,
saddr
,
16
);
secret
[
4
]
=
(
sport
<<
16
)
+
dport
;
seq
=
(
twothirdsMD4Transform
(
daddr
,
secret
)
&
((
1
<<
HASH_BITS
)
-
1
))
+
count
;
memcpy
(
hash
,
saddr
,
16
);
hash
[
4
]
=
(
sport
<<
16
)
+
dport
;
memcpy
(
&
hash
[
5
],
keyptr
->
secret
,
sizeof
(
__u32
)
*
7
);
seq
=
twothirdsMD4Transform
(
daddr
,
hash
)
&
HASH_MASK
;
seq
+=
keyptr
->
count
;
seq
+=
tv
.
tv_usec
+
tv
.
tv_sec
*
1000000
;
return
seq
;
}
EXPORT_SYMBOL
(
secure_tcpv6_sequence_number
);
__u32
secure_ipv6_id
(
__u32
*
daddr
)
{
static
time_t
rekey_time
;
static
__u32
secret
[
12
];
time_t
t
;
struct
keydata
*
keyptr
;
/*
* Pick a random secret every REKEY_INTERVAL seconds.
*/
t
=
CURRENT_TIME
;
if
(
!
rekey_time
||
(
t
-
rekey_time
)
>
REKEY_INTERVAL
)
{
rekey_time
=
t
;
/* First word is overwritten below. */
get_random_bytes
(
secret
,
sizeof
(
secret
));
}
keyptr
=
check_and_rekey
(
CURRENT_TIME
);
return
twothirdsMD4Transform
(
daddr
,
secret
);
return
halfMD4Transform
(
daddr
,
keyptr
->
secret
);
}
EXPORT_SYMBOL
(
secure_ipv6_id
);
...
...
@@ -2093,40 +2139,30 @@ EXPORT_SYMBOL(secure_ipv6_id);
__u32
secure_tcp_sequence_number
(
__u32
saddr
,
__u32
daddr
,
__u16
sport
,
__u16
dport
)
{
static
__u32
rekey_time
;
static
__u32
count
;
static
__u32
secret
[
12
];
struct
timeval
tv
;
__u32
seq
;
__u32
hash
[
4
];
struct
keydata
*
keyptr
;
/*
* Pick a random secret every REKEY_INTERVAL seconds.
*/
do_gettimeofday
(
&
tv
);
/* We need the usecs below... */
if
(
!
rekey_time
||
(
tv
.
tv_sec
-
rekey_time
)
>
REKEY_INTERVAL
)
{
rekey_time
=
tv
.
tv_sec
;
/* First three words are overwritten below. */
get_random_bytes
(
&
secret
[
3
],
sizeof
(
secret
)
-
12
);
count
=
(
tv
.
tv_sec
/
REKEY_INTERVAL
)
<<
HASH_BITS
;
}
keyptr
=
check_and_rekey
(
tv
.
tv_sec
);
/*
* Pick a unique starting offset for each TCP connection endpoints
* (saddr, daddr, sport, dport).
* Note that the words are placed into the first words to be
* mixed in with the halfMD4. This is because the starting
* vector is also a random secret (at secret+8), and further
* hashing fixed data into it isn't going to improve anything,
* so we should get started with the variable data.
* Note that the words are placed into the starting vector, which is
* then mixed with a partial MD4 over random data.
*/
secret
[
0
]
=
saddr
;
secret
[
1
]
=
daddr
;
secret
[
2
]
=
(
sport
<<
16
)
+
dport
;
seq
=
(
halfMD4Transform
(
secret
+
8
,
secret
)
&
((
1
<<
HASH_BITS
)
-
1
))
+
count
;
hash
[
0
]
=
saddr
;
hash
[
1
]
=
daddr
;
hash
[
2
]
=
(
sport
<<
16
)
+
dport
;
hash
[
3
]
=
keyptr
->
secret
[
11
];
seq
=
halfMD4Transform
(
hash
,
keyptr
->
secret
)
&
HASH_MASK
;
seq
+=
keyptr
->
count
;
/*
* As close as possible to RFC 793, which
* suggests using a 250 kHz clock.
...
...
@@ -2148,31 +2184,22 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
*/
__u32
secure_ip_id
(
__u32
daddr
)
{
static
time_t
rekey_time
;
static
__u32
secret
[
12
];
time_t
t
;
struct
keydata
*
keyptr
;
__u32
hash
[
4
];
/*
* Pick a random secret every REKEY_INTERVAL seconds.
*/
t
=
CURRENT_TIME
;
if
(
!
rekey_time
||
(
t
-
rekey_time
)
>
REKEY_INTERVAL
)
{
rekey_time
=
t
;
/* First word is overwritten below. */
get_random_bytes
(
secret
+
1
,
sizeof
(
secret
)
-
4
);
}
keyptr
=
check_and_rekey
(
CURRENT_TIME
);
/*
* Pick a unique starting offset for each IP destination.
* Note that the words are placed into the first words to be
* mixed in with the halfMD4. This is because the starting
* vector is also a random secret (at secret+8), and further
* hashing fixed data into it isn't going to improve anything,
* so we should get started with the variable data.
* The dest ip address is placed in the starting vector,
* which is then hashed with random data.
*/
secret
[
0
]
=
daddr
;
hash
[
0
]
=
daddr
;
hash
[
1
]
=
keyptr
->
secret
[
9
];
hash
[
2
]
=
keyptr
->
secret
[
10
];
hash
[
3
]
=
keyptr
->
secret
[
11
];
return
halfMD4Transform
(
secret
+
8
,
secret
);
return
halfMD4Transform
(
hash
,
keyptr
->
secret
);
}
#ifdef CONFIG_SYN_COOKIES
...
...
drivers/net/tg3.c
View file @
a4041f6f
...
...
@@ -23,6 +23,8 @@
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <asm/system.h>
#include <asm/io.h>
...
...
@@ -49,7 +51,9 @@
#endif
#ifdef NETIF_F_TSO
/* XXX some bug in tso firmware hangs tx cpu, disabled until fixed */
/* XXX Works but still disabled, decreases TCP performance to 7MB/sec even
* XXX over gigabit.
*/
#define TG3_DO_TSO 0
#else
#define TG3_DO_TSO 0
...
...
@@ -2390,9 +2394,20 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
if
(
skb
->
ip_summed
==
CHECKSUM_HW
)
base_flags
|=
TXD_FLAG_TCPUDP_CSUM
;
#if TG3_DO_TSO != 0
if
((
mss
=
skb_shinfo
(
skb
)
->
tso_size
)
!=
0
)
if
((
mss
=
skb_shinfo
(
skb
)
->
tso_size
)
!=
0
)
{
static
int
times
=
0
;
mss
+=
((
skb
->
h
.
th
->
doff
*
4
)
-
20
);
base_flags
|=
(
TXD_FLAG_CPU_PRE_DMA
|
TXD_FLAG_CPU_POST_DMA
);
if
(
times
++
<
5
)
{
printk
(
"tg3_xmit: tso_size[%u] tso_segs[%u] len[%u]
\n
"
,
(
unsigned
int
)
skb_shinfo
(
skb
)
->
tso_size
,
(
unsigned
int
)
skb_shinfo
(
skb
)
->
tso_segs
,
skb
->
len
);
}
}
#else
mss
=
0
;
#endif
...
...
@@ -2443,7 +2458,7 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
}
tg3_set_txd
(
tp
,
entry
,
mapping
,
len
,
base_flags
,
(
i
==
last
)
|
(
mss
<<
1
)
);
base_flags
,
(
i
==
last
));
entry
=
NEXT_TX
(
entry
);
}
...
...
@@ -2555,9 +2570,24 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
if
(
skb
->
ip_summed
==
CHECKSUM_HW
)
base_flags
|=
TXD_FLAG_TCPUDP_CSUM
;
#if TG3_DO_TSO != 0
if
((
mss
=
skb_shinfo
(
skb
)
->
tso_size
)
!=
0
)
if
((
mss
=
skb_shinfo
(
skb
)
->
tso_size
)
!=
0
)
{
static
int
times
=
0
;
/* TSO firmware wants TCP options included in
* tx descriptor MSS value.
*/
mss
+=
((
skb
->
h
.
th
->
doff
*
4
)
-
20
);
base_flags
|=
(
TXD_FLAG_CPU_PRE_DMA
|
TXD_FLAG_CPU_POST_DMA
);
if
(
times
++
<
5
)
{
printk
(
"tg3_xmit: tso_size[%u] tso_segs[%u] len[%u]
\n
"
,
(
unsigned
int
)
skb_shinfo
(
skb
)
->
tso_size
,
(
unsigned
int
)
skb_shinfo
(
skb
)
->
tso_segs
,
skb
->
len
);
}
}
#else
mss
=
0
;
#endif
...
...
@@ -2597,7 +2627,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
pci_unmap_addr_set
(
&
tp
->
tx_buffers
[
entry
],
mapping
,
mapping
);
tg3_set_txd
(
tp
,
entry
,
mapping
,
len
,
base_flags
,
(
i
==
last
)
|
(
mss
<<
1
)
);
base_flags
,
(
i
==
last
));
entry
=
NEXT_TX
(
entry
);
}
...
...
@@ -4329,9 +4359,11 @@ static int tg3_reset_hw(struct tg3 *tp)
}
#if TG3_DO_TSO != 0
if
(
tp
->
dev
->
features
&
NETIF_F_TSO
)
{
err
=
tg3_load_tso_firmware
(
tp
);
if
(
err
)
return
err
;
}
#endif
tp
->
tx_mode
=
TX_MODE_ENABLE
;
...
...
@@ -6752,9 +6784,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
dev
->
vlan_rx_register
=
tg3_vlan_rx_register
;
dev
->
vlan_rx_kill_vid
=
tg3_vlan_rx_kill_vid
;
#endif
#if TG3_DO_TSO != 0
dev
->
features
|=
NETIF_F_TSO
;
#endif
tp
=
dev
->
priv
;
tp
->
pdev
=
pdev
;
...
...
@@ -6855,6 +6884,17 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
}
else
tp
->
tg3_flags
&=
~
TG3_FLAG_RX_CHECKSUMS
;
#if TG3_DO_TSO != 0
if
(
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
==
ASIC_REV_5700
||
(
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
==
ASIC_REV_5701
&&
tp
->
pci_chip_rev_id
<=
CHIPREV_ID_5701_B2
))
{
/* Not TSO capable. */
dev
->
features
&=
~
NETIF_F_TSO
;
}
else
{
dev
->
features
|=
NETIF_F_TSO
;
}
#endif
err
=
register_netdev
(
dev
);
if
(
err
)
{
printk
(
KERN_ERR
PFX
"Cannot register net device, "
...
...
drivers/net/tun.c
View file @
a4041f6f
...
...
@@ -275,7 +275,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
total
+=
sizeof
(
pi
);
}
len
=
min
(
skb
->
len
,
len
);
len
=
min
_t
(
int
,
skb
->
len
,
len
);
skb_copy_datagram_iovec
(
skb
,
0
,
iv
,
len
);
total
+=
len
;
...
...
@@ -306,6 +306,8 @@ static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv,
return
-
EFAULT
;
len
+=
iv
[
i
].
iov_len
;
}
if
(
len
<
0
)
return
-
EINVAL
;
add_wait_queue
(
&
tun
->
read_wait
,
&
wait
);
while
(
len
)
{
...
...
include/net/ax25.h
View file @
a4041f6f
...
...
@@ -3,11 +3,14 @@
*
* Alan Cox (GW4PTS) 10/11/93
*/
#ifndef _AX25_H
#define _AX25_H
#include <linux/config.h>
#include <linux/ax25.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <asm/atomic.h>
#define AX25_T1CLAMPLO 1
#define AX25_T1CLAMPHI (30 * HZ)
...
...
@@ -66,6 +69,8 @@
#define AX25_UA 0x63
/* Unnumbered acknowledge */
#define AX25_FRMR 0x87
/* Frame reject */
#define AX25_UI 0x03
/* Unnumbered information */
#define AX25_XID 0xaf
/* Exchange information */
#define AX25_TEST 0xe3
/* Test */
#define AX25_PF 0x10
/* Poll/final bit for standard AX.25 */
#define AX25_EPF 0x01
/* Poll/final bit for extended AX.25 */
...
...
@@ -147,10 +152,12 @@ typedef struct {
typedef
struct
ax25_route
{
struct
ax25_route
*
next
;
atomic_t
ref
;
ax25_address
callsign
;
struct
net_device
*
dev
;
ax25_digi
*
digipeat
;
char
ip_mode
;
struct
timer_list
timer
;
}
ax25_route
;
typedef
struct
{
...
...
@@ -197,11 +204,12 @@ typedef struct ax25_cb {
#define ax25_sk(__sk) ((ax25_cb *)(__sk)->protinfo)
/* af_ax25.c */
extern
ax25_cb
*
volatile
ax25_list
;
extern
ax25_cb
*
ax25_list
;
extern
spinlock_t
ax25_list_lock
;
extern
void
ax25_free_cb
(
ax25_cb
*
);
extern
void
ax25_insert_socket
(
ax25_cb
*
);
struct
sock
*
ax25_find_listener
(
ax25_address
*
,
int
,
struct
net_device
*
,
int
);
struct
sock
*
ax25_
find
_socket
(
ax25_address
*
,
ax25_address
*
,
int
);
struct
sock
*
ax25_
get
_socket
(
ax25_address
*
,
ax25_address
*
,
int
);
extern
ax25_cb
*
ax25_find_cb
(
ax25_address
*
,
ax25_address
*
,
ax25_digi
*
,
struct
net_device
*
);
extern
struct
sock
*
ax25_addr_match
(
ax25_address
*
);
extern
void
ax25_send_to_raw
(
struct
sock
*
,
struct
sk_buff
*
,
int
);
...
...
@@ -224,6 +232,7 @@ extern void ax25_digi_invert(ax25_digi *, ax25_digi *);
/* ax25_dev.c */
extern
ax25_dev
*
ax25_dev_list
;
extern
spinlock_t
ax25_dev_lock
;
extern
ax25_dev
*
ax25_dev_ax25dev
(
struct
net_device
*
);
extern
ax25_dev
*
ax25_addr_ax25dev
(
ax25_address
*
);
extern
void
ax25_dev_device_up
(
struct
net_device
*
);
...
...
@@ -286,10 +295,16 @@ extern void ax25_rt_device_down(struct net_device *);
extern
int
ax25_rt_ioctl
(
unsigned
int
,
void
*
);
extern
int
ax25_rt_get_info
(
char
*
,
char
**
,
off_t
,
int
);
extern
int
ax25_rt_autobind
(
ax25_cb
*
,
ax25_address
*
);
extern
ax25_route
*
ax25_rt_find_route
(
ax25_address
*
,
struct
net_device
*
);
extern
ax25_route
*
ax25_rt_find_route
(
ax25_route
*
,
ax25_address
*
,
struct
net_device
*
);
extern
struct
sk_buff
*
ax25_rt_build_path
(
struct
sk_buff
*
,
ax25_address
*
,
ax25_address
*
,
ax25_digi
*
);
extern
void
ax25_rt_free
(
void
);
static
inline
void
ax25_put_route
(
ax25_route
*
ax25_rt
)
{
atomic_dec
(
&
ax25_rt
->
ref
);
}
/* ax25_std_in.c */
extern
int
ax25_std_frame_in
(
ax25_cb
*
,
struct
sk_buff
*
,
int
);
...
...
include/net/llc_actn.h
View file @
a4041f6f
...
...
@@ -45,4 +45,5 @@ extern int llc_station_ac_report_status(struct llc_station *station,
struct
sk_buff
*
skb
);
extern
int
llc_station_ac_report_status
(
struct
llc_station
*
station
,
struct
sk_buff
*
skb
);
extern
void
llc_station_ack_tmr_cb
(
unsigned
long
timeout_data
);
#endif
/* LLC_ACTN_H */
include/net/llc_c_ac.h
View file @
a4041f6f
...
...
@@ -211,4 +211,9 @@ extern int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock* sk,
struct
sk_buff
*
skb
);
extern
int
llc_conn_ac_send_i_rsp_as_ack
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
);
extern
int
llc_conn_ac_send_i_as_ack
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
);
extern
void
llc_conn_busy_tmr_cb
(
unsigned
long
timeout_data
);
extern
void
llc_conn_pf_cycle_tmr_cb
(
unsigned
long
timeout_data
);
extern
void
llc_conn_ack_tmr_cb
(
unsigned
long
timeout_data
);
extern
void
llc_conn_rej_tmr_cb
(
unsigned
long
timeout_data
);
#endif
/* LLC_C_AC_H */
include/net/llc_c_ev.h
View file @
a4041f6f
...
...
@@ -11,6 +11,9 @@
*
* See the GNU General Public License for more details.
*/
#include <net/sock.h>
/* Connection component state transition event qualifiers */
/* Types of events (possible values in 'ev->type') */
#define LLC_CONN_EV_TYPE_SIMPLE 1
...
...
@@ -293,4 +296,10 @@ extern int llc_conn_ev_qlfy_set_status_conflict(struct sock *sk,
struct
sk_buff
*
skb
);
extern
int
llc_conn_ev_qlfy_set_status_rst_done
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
);
static
__inline__
int
llc_conn_space
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
)
{
return
atomic_read
(
&
sk
->
rmem_alloc
)
+
skb
->
truesize
<
(
unsigned
)
sk
->
rcvbuf
;
}
#endif
/* LLC_C_EV_H */
include/net/llc_main.h
View file @
a4041f6f
...
...
@@ -16,7 +16,7 @@
#define LLC_TYPE_1 1
#define LLC_TYPE_2 2
#define LLC_P_TIME 2
#define LLC_ACK_TIME
3
#define LLC_ACK_TIME
1
#define LLC_REJ_TIME 3
#define LLC_BUSY_TIME 3
#define LLC_DEST_INVALID 0
/* Invalid LLC PDU type */
...
...
net/ax25/Config.in
View file @
a4041f6f
net/ax25/TODO
0 → 100644
View file @
a4041f6f
Do the ax25_list_lock, ax25_dev_lock, linkfail_lockreally, ax25_frag_lock and
listen_lock have to be bh-safe?
Do the netrom and rose locks have to be bh-safe?
A device might be deleted after lookup in the SIOCADDRT ioctl but before it's
being used.
Routes to a device being taken down might be deleted by ax25_rt_device_down
but added by somebody else before the device has been deleted fully.
Massive amounts of lock_kernel / unlock_kernel are just a temporary solution to
get around the removal of SOCKOPS_WRAP. A serious locking strategy has to be
implemented.
The ax25_rt_find_route synopsys is pervert but I somehow had to deal with
the race caused by the static variable in it's previous implementation.
Implement proper socket locking in netrom and rose.
Check socket locking when ax25_rcv is sending to raw sockets. In particular
ax25_send_to_raw() seems fishy. Heck - ax25_rcv is fishy.
Handle XID and TEST frames properly.
net/ax25/af_ax25.c
View file @
a4041f6f
/*
* AX.25 release 038
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* AX.25 006 Alan(GW4PTS) Nearly died of shock - it's working 8-)
* AX.25 007 Alan(GW4PTS) Removed the silliest bugs
* AX.25 008 Alan(GW4PTS) Cleaned up, fixed a few state machine problems, added callbacks
* AX.25 009 Alan(GW4PTS) Emergency patch kit to fix memory corruption
* AX.25 010 Alan(GW4PTS) Added RAW sockets/Digipeat.
* AX.25 011 Alan(GW4PTS) RAW socket and datagram fixes (thanks) - Raw sendto now gets PID right
* datagram sendto uses correct target address.
* AX.25 012 Alan(GW4PTS) Correct incoming connection handling, send DM to failed connects.
* Use skb->data not skb+1. Support sk->priority correctly.
* Correct receive on SOCK_DGRAM.
* AX.25 013 Alan(GW4PTS) Send DM to all unknown frames, missing initialiser fixed
* Leave spare SSID bits set (DAMA etc) - thanks for bug report,
* removed device registration (it's not used or needed). Clean up for
* gcc 2.5.8. PID to AX25_P_
* AX.25 014 Alan(GW4PTS) Cleanup and NET3 merge
* AX.25 015 Alan(GW4PTS) Internal test version.
* AX.25 016 Alan(GW4PTS) Semi Internal version for PI card
* work.
* AX.25 017 Alan(GW4PTS) Fixed some small bugs reported by
* G4KLX
* AX.25 018 Alan(GW4PTS) Fixed a small error in SOCK_DGRAM
* AX.25 019 Alan(GW4PTS) Clean ups for the non INET kernel and device ioctls in AX.25
* AX.25 020 Jonathan(G4KLX) /proc support and other changes.
* AX.25 021 Alan(GW4PTS) Added AX25_T1, AX25_N2, AX25_T3 as requested.
* AX.25 022 Jonathan(G4KLX) More work on the ax25 auto router and /proc improved (again)!
* Alan(GW4PTS) Added TIOCINQ/OUTQ
* AX.25 023 Alan(GW4PTS) Fixed shutdown bug
* AX.25 023 Alan(GW4PTS) Linus changed timers
* AX.25 024 Alan(GW4PTS) Small bug fixes
* AX.25 025 Alan(GW4PTS) More fixes, Linux 1.1.51 compatibility stuff, timers again!
* AX.25 026 Alan(GW4PTS) Small state fix.
* AX.25 027 Alan(GW4PTS) Socket close crash fixes.
* AX.25 028 Alan(GW4PTS) Callsign control including settings per uid.
* Small bug fixes.
* Protocol set by sockets only.
* Small changes to allow for start of NET/ROM layer.
* AX.25 028a Jonathan(G4KLX) Changes to state machine.
* AX.25 028b Jonathan(G4KLX) Extracted ax25 control block
* from sock structure.
* AX.25 029 Alan(GW4PTS) Combined 028b and some KA9Q code
* Jonathan(G4KLX) and removed all the old Berkeley, added IP mode registration.
* Darryl(G7LED) stuff. Cross-port digipeating. Minor fixes and enhancements.
* Alan(GW4PTS) Missed suser() on axassociate checks
* AX.25 030 Alan(GW4PTS) Added variable length headers.
* Jonathan(G4KLX) Added BPQ Ethernet interface.
* Steven(GW7RRM) Added digi-peating control ioctl.
* Added extended AX.25 support.
* Added AX.25 frame segmentation.
* Darryl(G7LED) Changed connect(), recvfrom(), sendto() sockaddr/addrlen to
* fall inline with bind() and new policy.
* Moved digipeating ctl to new ax25_dev structs.
* Fixed ax25_release(), set TCP_CLOSE, wakeup app
* context, THEN make the sock dead.
* Alan(GW4PTS) Cleaned up for single recvmsg methods.
* Alan(GW4PTS) Fixed not clearing error on connect failure.
* AX.25 031 Jonathan(G4KLX) Added binding to any device.
* Joerg(DL1BKE) Added DAMA support, fixed (?) digipeating, fixed buffer locking
* for "virtual connect" mode... Result: Probably the
* "Most Buggiest Code You've Ever Seen" (TM)
* HaJo(DD8NE) Implementation of a T5 (idle) timer
* Joerg(DL1BKE) Renamed T5 to IDLE and changed behaviour:
* the timer gets reloaded on every received or transmitted
* I frame for IP or NETROM. The idle timer is not active
* on "vanilla AX.25" connections. Furthermore added PACLEN
* to provide AX.25-layer based fragmentation (like WAMPES)
* AX.25 032 Joerg(DL1BKE) Fixed DAMA timeout error.
* ax25_send_frame() limits the number of enqueued
* datagrams per socket.
* AX.25 033 Jonathan(G4KLX) Removed auto-router.
* Hans(PE1AYX) Converted to Module.
* Joerg(DL1BKE) Moved BPQ Ethernet to separate driver.
* AX.25 034 Jonathan(G4KLX) 2.1 changes
* Alan(GW4PTS) Small POSIXisations
* AX.25 035 Alan(GW4PTS) Started fixing to the new
* format.
* Hans(PE1AYX) Fixed interface to IP layer.
* Alan(GW4PTS) Added asynchronous support.
* Frederic(F1OAT) Support for pseudo-digipeating.
* Jonathan(G4KLX) Support for packet forwarding.
* AX.25 036 Jonathan(G4KLX) Major restructuring.
* Joerg(DL1BKE) Fixed DAMA Slave.
* Jonathan(G4KLX) Fix wildcard listen parameter setting.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* AX.25 038 Matthias(DG2FEF) Small fixes to the syscall interface to make kernel
* independent of AX25_MAX_DIGIS used by applications.
* Tomi(OH2BNS) Fixed ax25_getname().
* Joerg(DL1BKE) Starting to phase out the support for full_sockaddr_ax25
* with only 6 digipeaters and sockaddr_ax25 in ax25_bind(),
* ax25_connect() and ax25_sendmsg()
* Joerg(DL1BKE) Added support for SO_BINDTODEVICE
* Arnaldo C. Melo s/suser/capable(CAP_NET_ADMIN)/, some more cleanups
* Michal Ostrowski Module initialization cleanup.
* Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Darryl Miles G7LED (dlm@g7led.demon.co.uk)
* Copyright (C) Steven Whitehouse GW7RRM (stevew@acm.org)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
* Copyright (C) Hans Alblas PE1AYX (hans@esrac.ele.tue.nl)
* Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
...
...
@@ -114,6 +23,7 @@
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/smp_lock.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <net/ax25.h>
...
...
@@ -134,13 +44,15 @@
#include <linux/netfilter.h>
#include <linux/sysctl.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <net/tcp.h>
#include <net/ip.h>
#include <net/arp.h>
ax25_cb
*
volatile
ax25_list
;
ax25_cb
*
ax25_list
;
spinlock_t
ax25_list_lock
=
SPIN_LOCK_UNLOCKED
;
static
struct
proto_ops
ax25_proto_ops
;
...
...
@@ -171,27 +83,24 @@ static void ax25_free_sock(struct sock *sk)
static
void
ax25_remove_socket
(
ax25_cb
*
ax25
)
{
ax25_cb
*
s
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
ax25_list_lock
);
if
((
s
=
ax25_list
)
==
ax25
)
{
ax25_list
=
s
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
ax25_list_lock
);
return
;
}
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
if
(
s
->
next
==
ax25
)
{
s
->
next
=
ax25
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
ax25_list_lock
);
return
;
}
s
=
s
->
next
;
}
restore_flags
(
flags
);
spin_unlock_bh
(
&
ax25_list_lock
);
}
/*
...
...
@@ -205,18 +114,21 @@ static void ax25_kill_by_device(struct net_device *dev)
if
((
ax25_dev
=
ax25_dev_ax25dev
(
dev
))
==
NULL
)
return
;
spin_lock_bh
(
&
ax25_list_lock
);
for
(
s
=
ax25_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
if
(
s
->
ax25_dev
==
ax25_dev
)
{
s
->
ax25_dev
=
NULL
;
ax25_disconnect
(
s
,
ENETUNREACH
);
}
}
spin_unlock_bh
(
&
ax25_list_lock
);
}
/*
* Handle device status changes.
*/
static
int
ax25_device_event
(
struct
notifier_block
*
this
,
unsigned
long
event
,
void
*
ptr
)
static
int
ax25_device_event
(
struct
notifier_block
*
this
,
unsigned
long
event
,
void
*
ptr
)
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
ptr
;
...
...
@@ -245,80 +157,73 @@ static int ax25_device_event(struct notifier_block *this,unsigned long event, vo
*/
void
ax25_insert_socket
(
ax25_cb
*
ax25
)
{
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
ax25_list_lock
);
ax25
->
next
=
ax25_list
;
ax25_list
=
ax25
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
ax25_list_lock
);
}
/*
* Find a socket that wants to accept the SABM we have just
* received.
*/
struct
sock
*
ax25_find_listener
(
ax25_address
*
addr
,
int
digi
,
struct
net_device
*
dev
,
int
type
)
struct
sock
*
ax25_find_listener
(
ax25_address
*
addr
,
int
digi
,
struct
net_device
*
dev
,
int
type
)
{
unsigned
long
flags
;
ax25_cb
*
s
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
ax25_list_lock
);
for
(
s
=
ax25_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
if
((
s
->
iamdigi
&&
!
digi
)
||
(
!
s
->
iamdigi
&&
digi
))
continue
;
if
(
s
->
sk
!=
NULL
&&
ax25cmp
(
&
s
->
source_addr
,
addr
)
==
0
&&
s
->
sk
->
type
==
type
&&
s
->
sk
->
state
==
TCP_LISTEN
)
{
/* If device is null we match any device */
if
(
s
->
ax25_dev
==
NULL
||
s
->
ax25_dev
->
dev
==
dev
)
{
restore_flags
(
flags
);
spin_unlock_bh
(
&
ax25_list_lock
);
return
s
->
sk
;
}
}
}
spin_unlock_bh
(
&
ax25_list_lock
);
restore_flags
(
flags
);
return
NULL
;
}
/*
* Find an AX.25 socket given both ends.
*/
struct
sock
*
ax25_find_socket
(
ax25_address
*
my_addr
,
ax25_address
*
dest_addr
,
int
type
)
struct
sock
*
ax25_get_socket
(
ax25_address
*
my_addr
,
ax25_address
*
dest_addr
,
int
type
)
{
struct
sock
*
sk
=
NULL
;
ax25_cb
*
s
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
ax25_list_lock
);
for
(
s
=
ax25_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
if
(
s
->
sk
!=
NULL
&&
ax25cmp
(
&
s
->
source_addr
,
my_addr
)
==
0
&&
ax25cmp
(
&
s
->
dest_addr
,
dest_addr
)
==
0
&&
s
->
sk
->
type
==
type
)
{
restore_flags
(
flags
);
return
s
->
sk
;
sk
=
s
->
sk
;
/* XXX Sleeps with spinlock held, use refcounts instead. XXX */
lock_sock
(
sk
);
break
;
}
}
restore_flags
(
flags
);
spin_unlock_bh
(
&
ax25_list_lock
);
return
NULL
;
return
sk
;
}
/*
* Find an AX.25 control block given both ends. It will only pick up
* floating AX.25 control blocks or non Raw socket bound control blocks.
*/
ax25_cb
*
ax25_find_cb
(
ax25_address
*
src_addr
,
ax25_address
*
dest_addr
,
ax25_digi
*
digi
,
struct
net_device
*
dev
)
ax25_cb
*
ax25_find_cb
(
ax25_address
*
src_addr
,
ax25_address
*
dest_addr
,
ax25_digi
*
digi
,
struct
net_device
*
dev
)
{
ax25_cb
*
s
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
ax25_list_lock
);
for
(
s
=
ax25_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
if
(
s
->
sk
!=
NULL
&&
s
->
sk
->
type
!=
SOCK_SEQPACKET
)
continue
;
...
...
@@ -334,12 +239,12 @@ ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, ax25_digi
if
(
s
->
digipeat
!=
NULL
&&
s
->
digipeat
->
ndigi
!=
0
)
continue
;
}
restore_flags
(
flags
);
spin_unlock_bh
(
&
ax25_list_lock
);
return
s
;
}
}
restore_flags
(
flags
);
spin_unlock_bh
(
&
ax25_list_lock
);
return
NULL
;
}
...
...
@@ -349,22 +254,21 @@ ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, ax25_digi
*/
struct
sock
*
ax25_addr_match
(
ax25_address
*
addr
)
{
unsigned
long
flags
;
struct
sock
*
sk
=
NULL
;
ax25_cb
*
s
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
ax25_list_lock
);
for
(
s
=
ax25_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
if
(
s
->
sk
!=
NULL
&&
ax25cmp
(
&
s
->
source_addr
,
addr
)
==
0
&&
s
->
sk
->
type
==
SOCK_RAW
)
{
restore_flags
(
flags
);
return
s
->
sk
;
if
(
s
->
sk
!=
NULL
&&
ax25cmp
(
&
s
->
source_addr
,
addr
)
==
0
&&
s
->
sk
->
type
==
SOCK_RAW
)
{
sk
=
s
->
sk
;
lock_sock
(
sk
);
break
;
}
}
spin_unlock_bh
(
&
ax25_list_lock
);
restore_flags
(
flags
);
return
NULL
;
return
sk
;
}
void
ax25_send_to_raw
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
,
int
proto
)
...
...
@@ -400,17 +304,16 @@ static void ax25_destroy_timer(unsigned long data)
}
/*
* This is called from user mode and the timers. Thus it protects itself
against
*
interrupt users but doesn't worry about being called during work.
*
Once it is removed from the queue no interrupt or bottom half will
* touch it and we are (fairly 8-) ) safe.
* This is called from user mode and the timers. Thus it protects itself
*
against interrupt users but doesn't worry about being called during
*
work. Once it is removed from the queue no interrupt or bottom half
*
will
touch it and we are (fairly 8-) ) safe.
*/
void
ax25_destroy_socket
(
ax25_cb
*
ax25
)
/* Not static as it's used by the timer */
void
ax25_destroy_socket
(
ax25_cb
*
ax25
)
{
struct
sk_buff
*
skb
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
(
);
ax25_remove_socket
(
ax25
);
ax25_stop_heartbeat
(
ax25
);
ax25_stop_t1timer
(
ax25
);
...
...
@@ -418,15 +321,17 @@ void ax25_destroy_socket(ax25_cb *ax25) /* Not static as it's used by the timer
ax25_stop_t3timer
(
ax25
);
ax25_stop_idletimer
(
ax25
);
ax25_remove_socket
(
ax25
);
ax25_clear_queues
(
ax25
);
/* Flush the queues */
if
(
ax25
->
sk
!=
NULL
)
{
while
((
skb
=
skb_dequeue
(
&
ax25
->
sk
->
receive_queue
))
!=
NULL
)
{
if
(
skb
->
sk
!=
ax25
->
sk
)
{
/* A pending connection */
if
(
skb
->
sk
!=
ax25
->
sk
)
{
/* A pending connection */
ax25_cb
*
sax25
=
ax25_sk
(
skb
->
sk
);
skb
->
sk
->
dead
=
1
;
/* Queue the unaccepted socket for death */
/* Queue the unaccepted socket for death */
skb
->
sk
->
dead
=
1
;
ax25_start_heartbeat
(
sax25
);
sax25
->
state
=
AX25_STATE_0
;
}
...
...
@@ -450,8 +355,6 @@ void ax25_destroy_socket(ax25_cb *ax25) /* Not static as it's used by the timer
}
else
{
ax25_free_cb
(
ax25
);
}
restore_flags
(
flags
);
}
/*
...
...
@@ -631,13 +534,14 @@ ax25_cb *ax25_create_cb(void)
* AX25 socket object
*/
static
int
ax25_setsockopt
(
struct
socket
*
sock
,
int
level
,
int
optname
,
char
*
optval
,
int
optlen
)
static
int
ax25_setsockopt
(
struct
socket
*
sock
,
int
level
,
int
optname
,
char
*
optval
,
int
optlen
)
{
struct
sock
*
sk
=
sock
->
sk
;
ax25_cb
*
ax25
=
ax25_sk
(
sk
)
;
ax25_cb
*
ax25
;
struct
net_device
*
dev
;
char
devname
[
IFNAMSIZ
];
int
opt
;
int
opt
,
res
=
0
;
if
(
level
!=
SOL_AX25
)
return
-
ENOPROTOOPT
;
...
...
@@ -648,98 +552,131 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, char *op
if
(
get_user
(
opt
,
(
int
*
)
optval
))
return
-
EFAULT
;
lock_sock
(
sk
);
ax25
=
ax25_sk
(
sk
);
switch
(
optname
)
{
case
AX25_WINDOW
:
if
(
ax25
->
modulus
==
AX25_MODULUS
)
{
if
(
opt
<
1
||
opt
>
7
)
return
-
EINVAL
;
if
(
opt
<
1
||
opt
>
7
)
{
res
=
-
EINVAL
;
break
;
}
}
else
{
if
(
opt
<
1
||
opt
>
63
)
return
-
EINVAL
;
if
(
opt
<
1
||
opt
>
63
)
{
res
=
-
EINVAL
;
break
;
}
}
ax25
->
window
=
opt
;
return
0
;
break
;
case
AX25_T1
:
if
(
opt
<
1
)
return
-
EINVAL
;
if
(
opt
<
1
)
{
res
=
-
EINVAL
;
break
;
}
ax25
->
rtt
=
(
opt
*
HZ
)
/
2
;
ax25
->
t1
=
opt
*
HZ
;
return
0
;
break
;
case
AX25_T2
:
if
(
opt
<
1
)
return
-
EINVAL
;
if
(
opt
<
1
)
{
res
=
-
EINVAL
;
break
;
}
ax25
->
t2
=
opt
*
HZ
;
return
0
;
break
;
case
AX25_N2
:
if
(
opt
<
1
||
opt
>
31
)
return
-
EINVAL
;
if
(
opt
<
1
||
opt
>
31
)
{
res
=
-
EINVAL
;
break
;
}
ax25
->
n2
=
opt
;
return
0
;
break
;
case
AX25_T3
:
if
(
opt
<
1
)
return
-
EINVAL
;
if
(
opt
<
1
)
{
res
=
-
EINVAL
;
break
;
}
ax25
->
t3
=
opt
*
HZ
;
return
0
;
break
;
case
AX25_IDLE
:
if
(
opt
<
0
)
return
-
EINVAL
;
if
(
opt
<
0
)
{
res
=
-
EINVAL
;
break
;
}
ax25
->
idle
=
opt
*
60
*
HZ
;
return
0
;
break
;
case
AX25_BACKOFF
:
if
(
opt
<
0
||
opt
>
2
)
return
-
EINVAL
;
if
(
opt
<
0
||
opt
>
2
)
{
res
=
-
EINVAL
;
break
;
}
ax25
->
backoff
=
opt
;
return
0
;
break
;
case
AX25_EXTSEQ
:
ax25
->
modulus
=
opt
?
AX25_EMODULUS
:
AX25_MODULUS
;
return
0
;
break
;
case
AX25_PIDINCL
:
ax25
->
pidincl
=
opt
?
1
:
0
;
return
0
;
break
;
case
AX25_IAMDIGI
:
ax25
->
iamdigi
=
opt
?
1
:
0
;
return
0
;
break
;
case
AX25_PACLEN
:
if
(
opt
<
16
||
opt
>
65535
)
return
-
EINVAL
;
if
(
opt
<
16
||
opt
>
65535
)
{
res
=
-
EINVAL
;
break
;
}
ax25
->
paclen
=
opt
;
return
0
;
break
;
case
SO_BINDTODEVICE
:
if
(
optlen
>
IFNAMSIZ
)
optlen
=
IFNAMSIZ
;
if
(
copy_from_user
(
devname
,
optval
,
optlen
))
return
-
EFAULT
;
if
(
optlen
>
IFNAMSIZ
)
optlen
=
IFNAMSIZ
;
if
(
copy_from_user
(
devname
,
optval
,
optlen
))
{
res
=
-
EFAULT
;
break
;
}
dev
=
dev_get_by_name
(
devname
);
if
(
dev
==
NULL
)
return
-
ENODEV
;
if
(
dev
==
NULL
)
{
res
=
-
ENODEV
;
break
;
}
if
(
sk
->
type
==
SOCK_SEQPACKET
&&
(
sock
->
state
!=
SS_UNCONNECTED
||
sk
->
state
==
TCP_LISTEN
))
return
-
EADDRNOTAVAIL
;
(
sock
->
state
!=
SS_UNCONNECTED
||
sk
->
state
==
TCP_LISTEN
))
{
res
=
-
EADDRNOTAVAIL
;
break
;
}
ax25
->
ax25_dev
=
ax25_dev_ax25dev
(
dev
);
ax25_fillin_cb
(
ax25
,
ax25
->
ax25_dev
);
return
0
;
break
;
default:
return
-
ENOPROTOOPT
;
res
=
-
ENOPROTOOPT
;
}
release_sock
(
sk
);
return
res
;
}
static
int
ax25_getsockopt
(
struct
socket
*
sock
,
int
level
,
int
optname
,
char
*
optval
,
int
*
optlen
)
static
int
ax25_getsockopt
(
struct
socket
*
sock
,
int
level
,
int
optname
,
char
*
optval
,
int
*
optlen
)
{
struct
sock
*
sk
=
sock
->
sk
;
ax25_cb
*
ax25
=
ax25_sk
(
sk
)
;
ax25_cb
*
ax25
;
struct
ax25_dev
*
ax25_dev
;
char
devname
[
IFNAMSIZ
];
void
*
valptr
;
...
...
@@ -758,6 +695,9 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op
valptr
=
(
void
*
)
&
val
;
length
=
min_t
(
unsigned
int
,
maxlen
,
sizeof
(
int
));
lock_sock
(
sk
);
ax25
=
ax25_sk
(
sk
);
switch
(
optname
)
{
case
AX25_WINDOW
:
val
=
ax25
->
window
;
...
...
@@ -819,8 +759,10 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op
break
;
default:
release_sock
(
sk
);
return
-
ENOPROTOOPT
;
}
release_sock
(
sk
);
if
(
put_user
(
length
,
optlen
))
return
-
EFAULT
;
...
...
@@ -831,14 +773,20 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op
static
int
ax25_listen
(
struct
socket
*
sock
,
int
backlog
)
{
struct
sock
*
sk
=
sock
->
sk
;
int
res
=
0
;
lock_sock
(
sk
);
if
(
sk
->
type
==
SOCK_SEQPACKET
&&
sk
->
state
!=
TCP_LISTEN
)
{
sk
->
max_ack_backlog
=
backlog
;
sk
->
state
=
TCP_LISTEN
;
return
0
;
goto
out
;
}
res
=
-
EOPNOTSUPP
;
return
-
EOPNOTSUPP
;
out:
release_sock
(
sk
);
return
res
;
}
int
ax25_create
(
struct
socket
*
sock
,
int
protocol
)
...
...
@@ -851,6 +799,7 @@ int ax25_create(struct socket *sock, int protocol)
if
(
protocol
==
0
||
protocol
==
PF_AX25
)
protocol
=
AX25_P_TEXT
;
break
;
case
SOCK_SEQPACKET
:
switch
(
protocol
)
{
case
0
:
...
...
@@ -883,6 +832,7 @@ int ax25_create(struct socket *sock, int protocol)
break
;
}
break
;
case
SOCK_RAW
:
break
;
default:
...
...
@@ -985,8 +935,10 @@ static int ax25_release(struct socket *sock)
struct
sock
*
sk
=
sock
->
sk
;
ax25_cb
*
ax25
;
if
(
sk
==
NULL
)
return
0
;
if
(
sk
==
NULL
)
return
0
;
lock_sock
(
sk
);
ax25
=
ax25_sk
(
sk
);
if
(
sk
->
type
==
SOCK_SEQPACKET
)
{
...
...
@@ -1007,6 +959,7 @@ static int ax25_release(struct socket *sock)
case
AX25_STATE_4
:
ax25_clear_queues
(
ax25
);
ax25
->
n2count
=
0
;
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
...
...
@@ -1048,6 +1001,7 @@ static int ax25_release(struct socket *sock)
sock
->
sk
=
NULL
;
sk
->
socket
=
NULL
;
/* Not used, but we should do this */
release_sock
(
sk
);
return
0
;
}
...
...
@@ -1061,20 +1015,19 @@ static int ax25_release(struct socket *sock)
static
int
ax25_bind
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
int
addr_len
)
{
struct
sock
*
sk
=
sock
->
sk
;
ax25_cb
*
ax25
=
ax25_sk
(
sk
);
struct
full_sockaddr_ax25
*
addr
=
(
struct
full_sockaddr_ax25
*
)
uaddr
;
ax25_address
*
call
;
ax25_dev
*
ax25_dev
=
NULL
;
if
(
sk
->
zapped
==
0
)
return
-
EINVAL
;
ax25_address
*
call
;
ax25_cb
*
ax25
;
int
err
=
0
;
if
(
addr_len
!=
sizeof
(
struct
sockaddr_ax25
)
&&
addr_len
!=
sizeof
(
struct
full_sockaddr_ax25
))
{
/* support for old structure may go away some time */
if
((
addr_len
<
sizeof
(
struct
sockaddr_ax25
)
+
sizeof
(
ax25_address
)
*
6
)
||
(
addr_len
>
sizeof
(
struct
full_sockaddr_ax25
)))
(
addr_len
>
sizeof
(
struct
full_sockaddr_ax25
)))
{
return
-
EINVAL
;
}
printk
(
KERN_WARNING
"ax25_bind(): %s uses old (6 digipeater) socket structure.
\n
"
,
current
->
comm
);
...
...
@@ -1084,8 +1037,17 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
return
-
EINVAL
;
call
=
ax25_findbyuid
(
current
->
euid
);
if
(
call
==
NULL
&&
ax25_uid_policy
&&
!
capable
(
CAP_NET_ADMIN
))
if
(
call
==
NULL
&&
ax25_uid_policy
&&
!
capable
(
CAP_NET_ADMIN
))
{
return
-
EACCES
;
}
lock_sock
(
sk
);
ax25
=
ax25_sk
(
sk
);
if
(
sk
->
zapped
==
0
)
{
err
=
-
EINVAL
;
goto
out
;
}
if
(
call
==
NULL
)
ax25
->
source_addr
=
addr
->
fsa_ax25
.
sax25_call
;
...
...
@@ -1095,17 +1057,20 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
/*
* User already set interface with SO_BINDTODEVICE
*/
if
(
ax25
->
ax25_dev
!=
NULL
)
goto
done
;
if
(
addr_len
>
sizeof
(
struct
sockaddr_ax25
)
&&
addr
->
fsa_ax25
.
sax25_ndigis
==
1
)
{
if
(
ax25cmp
(
&
addr
->
fsa_digipeater
[
0
],
&
null_ax25_address
)
!=
0
&&
(
ax25_dev
=
ax25_addr_ax25dev
(
&
addr
->
fsa_digipeater
[
0
]))
==
NULL
)
return
-
EADDRNOTAVAIL
;
(
ax25_dev
=
ax25_addr_ax25dev
(
&
addr
->
fsa_digipeater
[
0
]))
==
NULL
)
{
err
=
-
EADDRNOTAVAIL
;
goto
out
;
}
}
else
{
if
((
ax25_dev
=
ax25_addr_ax25dev
(
&
addr
->
fsa_ax25
.
sax25_call
))
==
NULL
)
return
-
EADDRNOTAVAIL
;
if
((
ax25_dev
=
ax25_addr_ax25dev
(
&
addr
->
fsa_ax25
.
sax25_call
))
==
NULL
)
{
err
=
-
EADDRNOTAVAIL
;
goto
out
;
}
}
if
(
ax25_dev
!=
NULL
)
...
...
@@ -1114,41 +1079,24 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
done:
ax25_insert_socket
(
ax25
);
sk
->
zapped
=
0
;
out:
release_sock
(
sk
);
return
0
;
}
/*
* FIXME: nonblock behaviour looks like it may have a bug.
*/
static
int
ax25_connect
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
int
addr_len
,
int
flags
)
static
int
ax25_connect
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
int
addr_len
,
int
flags
)
{
struct
sock
*
sk
=
sock
->
sk
;
ax25_cb
*
ax25
=
ax25_sk
(
sk
);
struct
full_sockaddr_ax25
*
fsa
=
(
struct
full_sockaddr_ax25
*
)
uaddr
;
ax25_digi
*
digi
=
NULL
;
int
ct
=
0
,
err
;
/* deal with restarts */
if
(
sock
->
state
==
SS_CONNECTING
)
{
switch
(
sk
->
state
)
{
case
TCP_SYN_SENT
:
/* still trying */
return
-
EINPROGRESS
;
case
TCP_ESTABLISHED
:
/* connection established */
sock
->
state
=
SS_CONNECTED
;
return
0
;
case
TCP_CLOSE
:
/* connection refused */
sock
->
state
=
SS_UNCONNECTED
;
return
-
ECONNREFUSED
;
}
}
if
(
sk
->
state
==
TCP_ESTABLISHED
&&
sk
->
type
==
SOCK_SEQPACKET
)
return
-
EISCONN
;
/* No reconnect on a seqpacket socket */
sk
->
state
=
TCP_CLOSE
;
sock
->
state
=
SS_UNCONNECTED
;
int
ct
=
0
,
err
=
0
;
/*
* some sanity checks. code further down depends on this
...
...
@@ -1162,8 +1110,9 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
else
if
(
addr_len
!=
sizeof
(
struct
full_sockaddr_ax25
))
{
/* support for old structure may go away some time */
if
((
addr_len
<
sizeof
(
struct
sockaddr_ax25
)
+
sizeof
(
ax25_address
)
*
6
)
||
(
addr_len
>
sizeof
(
struct
full_sockaddr_ax25
)))
(
addr_len
>
sizeof
(
struct
full_sockaddr_ax25
)))
{
return
-
EINVAL
;
}
printk
(
KERN_WARNING
"ax25_connect(): %s uses old (6 digipeater) socket structure.
\n
"
,
current
->
comm
);
...
...
@@ -1172,6 +1121,34 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
if
(
fsa
->
fsa_ax25
.
sax25_family
!=
AF_AX25
)
return
-
EINVAL
;
lock_sock
(
sk
);
/* deal with restarts */
if
(
sock
->
state
==
SS_CONNECTING
)
{
switch
(
sk
->
state
)
{
case
TCP_SYN_SENT
:
/* still trying */
err
=
-
EINPROGRESS
;
goto
out
;
case
TCP_ESTABLISHED
:
/* connection established */
sock
->
state
=
SS_CONNECTED
;
goto
out
;
case
TCP_CLOSE
:
/* connection refused */
sock
->
state
=
SS_UNCONNECTED
;
err
=
-
ECONNREFUSED
;
goto
out
;
}
}
if
(
sk
->
state
==
TCP_ESTABLISHED
&&
sk
->
type
==
SOCK_SEQPACKET
)
{
err
=
-
EISCONN
;
/* No reconnect on a seqpacket socket */
goto
out
;
}
sk
->
state
=
TCP_CLOSE
;
sock
->
state
=
SS_UNCONNECTED
;
if
(
ax25
->
digipeat
!=
NULL
)
{
kfree
(
ax25
->
digipeat
);
ax25
->
digipeat
=
NULL
;
...
...
@@ -1180,13 +1157,18 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
/*
* Handle digi-peaters to be used.
*/
if
(
addr_len
>
sizeof
(
struct
sockaddr_ax25
)
&&
fsa
->
fsa_ax25
.
sax25_ndigis
!=
0
)
{
if
(
addr_len
>
sizeof
(
struct
sockaddr_ax25
)
&&
fsa
->
fsa_ax25
.
sax25_ndigis
!=
0
)
{
/* Valid number of digipeaters ? */
if
(
fsa
->
fsa_ax25
.
sax25_ndigis
<
1
||
fsa
->
fsa_ax25
.
sax25_ndigis
>
AX25_MAX_DIGIS
)
return
-
EINVAL
;
if
(
fsa
->
fsa_ax25
.
sax25_ndigis
<
1
||
fsa
->
fsa_ax25
.
sax25_ndigis
>
AX25_MAX_DIGIS
)
{
err
=
-
EINVAL
;
goto
out
;
}
if
((
digi
=
kmalloc
(
sizeof
(
ax25_digi
),
GFP_KERNEL
))
==
NULL
)
return
-
ENOBUFS
;
if
((
digi
=
kmalloc
(
sizeof
(
ax25_digi
),
GFP_KERNEL
))
==
NULL
)
{
err
=
-
ENOBUFS
;
goto
out
;
}
digi
->
ndigi
=
fsa
->
fsa_ax25
.
sax25_ndigis
;
digi
->
lastrepeat
=
-
1
;
...
...
@@ -1214,19 +1196,24 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
printk
(
KERN_WARNING
"ax25_connect(): %s uses autobind, please contact jreuter@yaina.de
\n
"
,
current
->
comm
);
if
((
err
=
ax25_rt_autobind
(
ax25
,
&
fsa
->
fsa_ax25
.
sax25_call
))
<
0
)
return
err
;
goto
out
;
ax25_fillin_cb
(
ax25
,
ax25
->
ax25_dev
);
ax25_insert_socket
(
ax25
);
}
else
{
if
(
ax25
->
ax25_dev
==
NULL
)
return
-
EHOSTUNREACH
;
if
(
ax25
->
ax25_dev
==
NULL
)
{
err
=
-
EHOSTUNREACH
;
goto
out
;
}
}
if
(
sk
->
type
==
SOCK_SEQPACKET
&&
ax25_find_cb
(
&
ax25
->
source_addr
,
&
fsa
->
fsa_ax25
.
sax25_call
,
digi
,
ax25
->
ax25_dev
->
dev
))
{
if
(
digi
!=
NULL
)
kfree
(
digi
);
return
-
EADDRINUSE
;
/* Already such a connection */
if
(
digi
!=
NULL
)
kfree
(
digi
);
err
=
-
EADDRINUSE
;
/* Already such a connection */
goto
out
;
}
ax25
->
dest_addr
=
fsa
->
fsa_ax25
.
sax25_call
;
...
...
@@ -1236,7 +1223,7 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
if
(
sk
->
type
!=
SOCK_SEQPACKET
)
{
sock
->
state
=
SS_CONNECTED
;
sk
->
state
=
TCP_ESTABLISHED
;
return
0
;
goto
out
;
}
/* Move to connecting socket, ax.25 lapb WAIT_UA.. */
...
...
@@ -1252,8 +1239,7 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
#ifdef CONFIG_AX25_DAMA_SLAVE
case
AX25_PROTO_DAMA_SLAVE
:
ax25
->
modulus
=
AX25_MODULUS
;
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_WINDOW
];
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_WINDOW
];
if
(
ax25
->
ax25_dev
->
dama
.
slave
)
ax25_ds_establish_data_link
(
ax25
);
else
...
...
@@ -1267,30 +1253,43 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
ax25_start_heartbeat
(
ax25
);
/* Now the loop */
if
(
sk
->
state
!=
TCP_ESTABLISHED
&&
(
flags
&
O_NONBLOCK
))
return
-
EINPROGRESS
;
if
(
sk
->
state
!=
TCP_ESTABLISHED
&&
(
flags
&
O_NONBLOCK
))
{
err
=
-
EINPROGRESS
;
goto
out
;
}
cli
();
/* To avoid races on the sleep */
if
(
sk
->
state
==
TCP_SYN_SENT
)
{
struct
task_struct
*
tsk
=
current
;
DECLARE_WAITQUEUE
(
wait
,
tsk
);
/* A DM or timeout will go to closed, a UA will go to ABM */
while
(
sk
->
state
==
TCP_SYN_SENT
)
{
interruptible_sleep_on
(
sk
->
sleep
);
if
(
signal_pending
(
current
))
{
sti
();
add_wait_queue
(
sk
->
sleep
,
&
wait
);
for
(;;)
{
if
(
sk
->
state
!=
TCP_SYN_SENT
)
break
;
set_current_state
(
TASK_INTERRUPTIBLE
);
release_sock
(
sk
);
if
(
!
signal_pending
(
tsk
))
{
schedule
();
lock_sock
(
sk
);
continue
;
}
return
-
ERESTARTSYS
;
}
current
->
state
=
TASK_RUNNING
;
remove_wait_queue
(
sk
->
sleep
,
&
wait
);
}
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
{
/* Not in ABM, not in WAIT_UA -> failed */
sti
();
sock
->
state
=
SS_UNCONNECTED
;
return
sock_error
(
sk
);
/* Always set at this point */
err
=
sock_error
(
sk
);
/* Always set at this point */
goto
out
;
}
sock
->
state
=
SS_CONNECTED
;
sti
();
out:
release_sock
(
sk
);
return
0
;
}
...
...
@@ -1298,9 +1297,12 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
static
int
ax25_accept
(
struct
socket
*
sock
,
struct
socket
*
newsock
,
int
flags
)
{
struct
sock
*
sk
;
struct
sock
*
newsk
;
struct
task_struct
*
tsk
=
current
;
DECLARE_WAITQUEUE
(
wait
,
tsk
)
;
struct
sk_buff
*
skb
;
struct
sock
*
newsk
;
struct
sock
*
sk
;
int
err
=
0
;
if
(
sock
->
state
!=
SS_UNCONNECTED
)
return
-
EINVAL
;
...
...
@@ -1308,26 +1310,40 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
if
((
sk
=
sock
->
sk
)
==
NULL
)
return
-
EINVAL
;
if
(
sk
->
type
!=
SOCK_SEQPACKET
)
return
-
EOPNOTSUPP
;
lock_sock
(
sk
);
if
(
sk
->
type
!=
SOCK_SEQPACKET
)
{
err
=
-
EOPNOTSUPP
;
goto
out
;
}
if
(
sk
->
state
!=
TCP_LISTEN
)
return
-
EINVAL
;
if
(
sk
->
state
!=
TCP_LISTEN
)
{
err
=
-
EINVAL
;
goto
out
;
}
/*
* The read queue this time is holding sockets ready to use
* hooked into the SABM we saved
*/
do
{
if
((
skb
=
skb_dequeue
(
&
sk
->
receive_queue
))
==
NULL
)
{
add_wait_queue
(
sk
->
sleep
,
&
wait
);
for
(;;)
{
skb
=
skb_dequeue
(
&
sk
->
receive_queue
);
if
(
skb
)
break
;
current
->
state
=
TASK_INTERRUPTIBLE
;
release_sock
(
sk
);
if
(
flags
&
O_NONBLOCK
)
return
-
EWOULDBLOCK
;
interruptible_sleep_on
(
sk
->
sleep
);
if
(
signal_pending
(
current
))
if
(
!
signal_pending
(
tsk
))
{
schedule
();
lock_sock
(
sk
);
continue
;
}
return
-
ERESTARTSYS
;
}
}
while
(
skb
==
NULL
);
current
->
state
=
TASK_RUNNING
;
remove_wait_queue
(
sk
->
sleep
,
&
wait
);
newsk
=
skb
->
sk
;
newsk
->
pair
=
NULL
;
...
...
@@ -1340,19 +1356,29 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
newsock
->
sk
=
newsk
;
newsock
->
state
=
SS_CONNECTED
;
return
0
;
out:
release_sock
(
sk
);
return
err
;
}
static
int
ax25_getname
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
int
*
uaddr_len
,
int
peer
)
static
int
ax25_getname
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
int
*
uaddr_len
,
int
peer
)
{
struct
sock
*
sk
=
sock
->
sk
;
ax25_cb
*
ax25
=
ax25_sk
(
sk
);
struct
full_sockaddr_ax25
*
fsa
=
(
struct
full_sockaddr_ax25
*
)
uaddr
;
struct
sock
*
sk
=
sock
->
sk
;
unsigned
char
ndigi
,
i
;
ax25_cb
*
ax25
;
int
err
=
0
;
lock_sock
(
sk
);
ax25
=
ax25_sk
(
sk
);
if
(
peer
!=
0
)
{
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
return
-
ENOTCONN
;
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
{
err
=
-
ENOTCONN
;
goto
out
;
}
fsa
->
fsa_ax25
.
sax25_family
=
AF_AX25
;
fsa
->
fsa_ax25
.
sax25_call
=
ax25
->
dest_addr
;
...
...
@@ -1377,41 +1403,53 @@ static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_
}
}
*
uaddr_len
=
sizeof
(
struct
full_sockaddr_ax25
);
return
0
;
out:
release_sock
(
sk
);
return
err
;
}
static
int
ax25_sendmsg
(
struct
socket
*
sock
,
struct
msghdr
*
msg
,
int
len
,
struct
scm_cookie
*
scm
)
static
int
ax25_sendmsg
(
struct
socket
*
sock
,
struct
msghdr
*
msg
,
int
len
,
struct
scm_cookie
*
scm
)
{
struct
sock
*
sk
=
sock
->
sk
;
ax25_cb
*
ax25
=
ax25_sk
(
sk
);
struct
sockaddr_ax25
*
usax
=
(
struct
sockaddr_ax25
*
)
msg
->
msg_name
;
int
err
;
struct
sock
*
sk
=
sock
->
sk
;
struct
sockaddr_ax25
sax
;
struct
sk_buff
*
skb
;
ax25_digi
dtmp
,
*
dp
;
unsigned
char
*
asmptr
;
int
size
;
ax25_digi
*
dp
;
ax25_digi
dtmp
;
int
lv
;
int
addr_len
=
msg
->
msg_namelen
;
ax25_cb
*
ax25
;
int
lv
,
size
,
err
,
addr_len
=
msg
->
msg_namelen
;
if
(
msg
->
msg_flags
&
~
(
MSG_DONTWAIT
|
MSG_EOR
))
if
(
msg
->
msg_flags
&
~
(
MSG_DONTWAIT
|
MSG_EOR
))
{
return
-
EINVAL
;
}
lock_sock
(
sk
);
ax25
=
ax25_sk
(
sk
);
if
(
sk
->
zapped
)
return
-
EADDRNOTAVAIL
;
if
(
sk
->
zapped
)
{
err
=
-
EADDRNOTAVAIL
;
goto
out
;
}
if
(
sk
->
shutdown
&
SEND_SHUTDOWN
)
{
send_sig
(
SIGPIPE
,
current
,
0
);
return
-
EPIPE
;
err
=
-
EPIPE
;
goto
out
;
}
if
(
ax25
->
ax25_dev
==
NULL
)
return
-
ENETUNREACH
;
if
(
ax25
->
ax25_dev
==
NULL
)
{
err
=
-
ENETUNREACH
;
goto
out
;
}
if
(
usax
!=
NULL
)
{
if
(
usax
->
sax25_family
!=
AF_AX25
)
return
-
EINVAL
;
if
(
usax
->
sax25_family
!=
AF_AX25
)
{
err
=
-
EINVAL
;
goto
out
;
}
if
(
addr_len
==
sizeof
(
struct
sockaddr_ax25
))
{
printk
(
KERN_WARNING
"ax25_sendmsg(): %s uses obsolete socket structure
\n
"
,
...
...
@@ -1420,8 +1458,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
else
if
(
addr_len
!=
sizeof
(
struct
full_sockaddr_ax25
))
{
/* support for old structure may go away some time */
if
((
addr_len
<
sizeof
(
struct
sockaddr_ax25
)
+
sizeof
(
ax25_address
)
*
6
)
||
(
addr_len
>
sizeof
(
struct
full_sockaddr_ax25
)))
return
-
EINVAL
;
(
addr_len
>
sizeof
(
struct
full_sockaddr_ax25
)))
{
err
=
-
EINVAL
;
goto
out
;
}
printk
(
KERN_WARNING
"ax25_sendmsg(): %s uses old (6 digipeater) socket structure.
\n
"
,
current
->
comm
);
...
...
@@ -1432,8 +1472,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
struct
full_sockaddr_ax25
*
fsa
=
(
struct
full_sockaddr_ax25
*
)
usax
;
/* Valid number of digipeaters ? */
if
(
usax
->
sax25_ndigis
<
1
||
usax
->
sax25_ndigis
>
AX25_MAX_DIGIS
)
return
-
EINVAL
;
if
(
usax
->
sax25_ndigis
<
1
||
usax
->
sax25_ndigis
>
AX25_MAX_DIGIS
)
{
err
=
-
EINVAL
;
goto
out
;
}
dtmp
.
ndigi
=
usax
->
sax25_ndigis
;
...
...
@@ -1447,8 +1489,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
}
sax
=
*
usax
;
if
(
sk
->
type
==
SOCK_SEQPACKET
&&
ax25cmp
(
&
ax25
->
dest_addr
,
&
sax
.
sax25_call
)
!=
0
)
return
-
EISCONN
;
if
(
sk
->
type
==
SOCK_SEQPACKET
&&
ax25cmp
(
&
ax25
->
dest_addr
,
&
sax
.
sax25_call
)
!=
0
)
{
err
=
-
EISCONN
;
goto
out
;
}
if
(
usax
->
sax25_ndigis
==
0
)
dp
=
NULL
;
else
...
...
@@ -1459,8 +1503,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
* it has become closed (not started closed) and is VC
* we ought to SIGPIPE, EPIPE
*/
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
return
-
ENOTCONN
;
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
{
err
=
-
ENOTCONN
;
goto
out
;
}
sax
.
sax25_family
=
AF_AX25
;
sax
.
sax25_call
=
ax25
->
dest_addr
;
dp
=
ax25
->
digipeat
;
...
...
@@ -1474,8 +1520,9 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
/* Assume the worst case */
size
=
len
+
3
+
ax25_addr_size
(
dp
)
+
AX25_BPQ_HEADER_LEN
;
if
((
skb
=
sock_alloc_send_skb
(
sk
,
size
,
msg
->
msg_flags
&
MSG_DONTWAIT
,
&
err
))
==
NULL
)
return
err
;
skb
=
sock_alloc_send_skb
(
sk
,
size
,
msg
->
msg_flags
&
MSG_DONTWAIT
,
&
err
);
if
(
skb
==
NULL
)
goto
out
;
skb_reserve
(
skb
,
size
-
len
);
...
...
@@ -1497,14 +1544,17 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
/* Connected mode sockets go via the LAPB machine */
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
{
kfree_skb
(
skb
);
return
-
ENOTCONN
;
err
=
-
ENOTCONN
;
goto
out
;
}
/* Shove it onto the queue and kick */
ax25_output
(
ax25
,
ax25
->
paclen
,
skb
);
return
len
;
}
else
{
err
=
len
;
goto
out
;
}
asmptr
=
skb_push
(
skb
,
1
+
ax25_addr_size
(
dp
));
SOCK_DEBUG
(
sk
,
"Building AX.25 Header (dp=%p).
\n
"
,
dp
);
...
...
@@ -1530,27 +1580,37 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
ax25_queue_xmit
(
skb
);
return
len
;
}
err
=
len
;
out:
release_sock
(
sk
);
return
err
;
}
static
int
ax25_recvmsg
(
struct
socket
*
sock
,
struct
msghdr
*
msg
,
int
size
,
int
flags
,
struct
scm_cookie
*
scm
)
static
int
ax25_recvmsg
(
struct
socket
*
sock
,
struct
msghdr
*
msg
,
int
size
,
int
flags
,
struct
scm_cookie
*
scm
)
{
struct
sock
*
sk
=
sock
->
sk
;
int
copied
;
struct
sk_buff
*
skb
;
int
er
;
int
copied
;
int
err
=
0
;
lock_sock
(
sk
);
/*
* This works for seqpacket too. The receiver has ordered the
* queue for us! We do one quick check first though
*/
if
(
sk
->
type
==
SOCK_SEQPACKET
&&
sk
->
state
!=
TCP_ESTABLISHED
)
return
-
ENOTCONN
;
if
(
sk
->
type
==
SOCK_SEQPACKET
&&
sk
->
state
!=
TCP_ESTABLISHED
)
{
err
=
-
ENOTCONN
;
goto
out
;
}
/* Now we can treat all alike */
if
((
skb
=
skb_recv_datagram
(
sk
,
flags
&
~
MSG_DONTWAIT
,
flags
&
MSG_DONTWAIT
,
&
er
))
==
NULL
)
return
er
;
skb
=
skb_recv_datagram
(
sk
,
flags
&
~
MSG_DONTWAIT
,
flags
&
MSG_DONTWAIT
,
&
err
);
if
(
skb
==
NULL
)
goto
out
;
if
(
!
ax25_sk
(
sk
)
->
pidincl
)
skb_pull
(
skb
,
1
);
/* Remove PID */
...
...
@@ -1590,8 +1650,12 @@ static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int f
}
skb_free_datagram
(
sk
,
skb
);
err
=
copied
;
return
copied
;
out:
release_sock
(
sk
);
return
err
;
}
static
int
ax25_shutdown
(
struct
socket
*
sk
,
int
how
)
...
...
@@ -1603,14 +1667,17 @@ static int ax25_shutdown(struct socket *sk, int how)
static
int
ax25_ioctl
(
struct
socket
*
sock
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
struct
sock
*
sk
=
sock
->
sk
;
int
res
=
0
;
lock_sock
(
sk
);
switch
(
cmd
)
{
case
TIOCOUTQ
:
{
long
amount
;
amount
=
sk
->
sndbuf
-
atomic_read
(
&
sk
->
wmem_alloc
);
if
(
amount
<
0
)
amount
=
0
;
return
put_user
(
amount
,
(
int
*
)
arg
);
res
=
put_user
(
amount
,
(
int
*
)
arg
);
break
;
}
case
TIOCINQ
:
{
...
...
@@ -1619,49 +1686,70 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
/* These two are safe on a single CPU system as only user tasks fiddle here */
if
((
skb
=
skb_peek
(
&
sk
->
receive_queue
))
!=
NULL
)
amount
=
skb
->
len
;
return
put_user
(
amount
,
(
int
*
)
arg
);
res
=
put_user
(
amount
,
(
int
*
)
arg
);
break
;
}
case
SIOCGSTAMP
:
if
(
sk
!=
NULL
)
{
if
(
sk
->
stamp
.
tv_sec
==
0
)
return
-
ENOENT
;
return
copy_to_user
((
void
*
)
arg
,
&
sk
->
stamp
,
sizeof
(
struct
timeval
))
?
-
EFAULT
:
0
;
if
(
sk
->
stamp
.
tv_sec
==
0
)
{
res
=
-
ENOENT
;
break
;
}
return
-
EINVAL
;
res
=
copy_to_user
((
void
*
)
arg
,
&
sk
->
stamp
,
sizeof
(
struct
timeval
))
?
-
EFAULT
:
0
;
break
;
}
res
=
-
EINVAL
;
break
;
case
SIOCAX25ADDUID
:
/* Add a uid to the uid/call map table */
case
SIOCAX25DELUID
:
/* Delete a uid from the uid/call map table */
case
SIOCAX25GETUID
:
{
struct
sockaddr_ax25
sax25
;
if
(
copy_from_user
(
&
sax25
,
(
void
*
)
arg
,
sizeof
(
sax25
)))
return
-
EFAULT
;
return
ax25_uid_ioctl
(
cmd
,
&
sax25
);
if
(
copy_from_user
(
&
sax25
,
(
void
*
)
arg
,
sizeof
(
sax25
)))
{
res
=
-
EFAULT
;
break
;
}
res
=
ax25_uid_ioctl
(
cmd
,
&
sax25
);
break
;
}
case
SIOCAX25NOUID
:
{
/* Set the default policy (default/bar) */
long
amount
;
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
if
(
get_user
(
amount
,
(
long
*
)
arg
))
return
-
EFAULT
;
if
(
amount
>
AX25_NOUID_BLOCK
)
return
-
EINVAL
;
if
(
!
capable
(
CAP_NET_ADMIN
))
{
res
=
-
EPERM
;
break
;
}
if
(
get_user
(
amount
,
(
long
*
)
arg
))
{
res
=
-
EFAULT
;
break
;
}
if
(
amount
>
AX25_NOUID_BLOCK
)
{
res
=
-
EINVAL
;
break
;
}
ax25_uid_policy
=
amount
;
return
0
;
res
=
0
;
break
;
}
case
SIOCADDRT
:
case
SIOCDELRT
:
case
SIOCAX25OPTRT
:
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
return
ax25_rt_ioctl
(
cmd
,
(
void
*
)
arg
);
if
(
!
capable
(
CAP_NET_ADMIN
))
{
res
=
-
EPERM
;
break
;
}
res
=
ax25_rt_ioctl
(
cmd
,
(
void
*
)
arg
);
break
;
case
SIOCAX25CTLCON
:
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
return
ax25_ctl_ioctl
(
cmd
,
(
void
*
)
arg
);
if
(
!
capable
(
CAP_NET_ADMIN
))
{
res
=
-
EPERM
;
break
;
}
res
=
ax25_ctl_ioctl
(
cmd
,
(
void
*
)
arg
);
break
;
case
SIOCAX25GETINFO
:
case
SIOCAX25GETINFOOLD
:
{
...
...
@@ -1697,23 +1785,33 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
warned
=
1
;
}
if
(
copy_to_user
((
void
*
)
arg
,
&
ax25_info
,
sizeof
(
struct
ax25_info_struct_depreciated
)))
return
-
EFAULT
;
if
(
copy_to_user
((
void
*
)
arg
,
&
ax25_info
,
sizeof
(
struct
ax25_info_struct_depreciated
)))
{
res
=
-
EFAULT
;
break
;
}
}
else
{
if
(
copy_to_user
((
void
*
)
arg
,
&
ax25_info
,
sizeof
(
struct
ax25_info_struct
)))
return
-
EINVAL
;
if
(
copy_to_user
((
void
*
)
arg
,
&
ax25_info
,
sizeof
(
struct
ax25_info_struct
)))
{
res
=
-
EINVAL
;
break
;
}
return
0
;
}
res
=
0
;
break
;
}
case
SIOCAX25ADDFWD
:
case
SIOCAX25DELFWD
:
{
struct
ax25_fwd_struct
ax25_fwd
;
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
if
(
copy_from_user
(
&
ax25_fwd
,
(
void
*
)
arg
,
sizeof
(
ax25_fwd
)))
return
-
EFAULT
;
return
ax25_fwd_ioctl
(
cmd
,
&
ax25_fwd
);
if
(
!
capable
(
CAP_NET_ADMIN
))
{
res
=
-
EPERM
;
break
;
}
if
(
copy_from_user
(
&
ax25_fwd
,
(
void
*
)
arg
,
sizeof
(
ax25_fwd
)))
{
res
=
-
EFAULT
;
break
;
}
res
=
ax25_fwd_ioctl
(
cmd
,
&
ax25_fwd
);
break
;
}
case
SIOCGIFADDR
:
...
...
@@ -1726,14 +1824,16 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case
SIOCSIFNETMASK
:
case
SIOCGIFMETRIC
:
case
SIOCSIFMETRIC
:
return
-
EINVAL
;
res
=
-
EINVAL
;
break
;
default:
return
dev_ioctl
(
cmd
,
(
void
*
)
arg
);
res
=
dev_ioctl
(
cmd
,
(
void
*
)
arg
);
break
;
}
release_sock
(
sk
);
/*NOTREACHED*/
return
0
;
return
res
;
}
static
int
ax25_get_info
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
...
...
@@ -1744,7 +1844,7 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length)
off_t
pos
=
0
;
off_t
begin
=
0
;
cli
(
);
spin_lock_bh
(
&
ax25_list_lock
);
/*
* New format:
...
...
@@ -1799,7 +1899,7 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length)
break
;
}
s
ti
(
);
s
pin_unlock_bh
(
&
ax25_list_lock
);
*
start
=
buffer
+
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
...
...
@@ -1814,7 +1914,7 @@ static struct net_proto_family ax25_family_ops = {
.
create
=
ax25_create
,
};
static
struct
proto_ops
SOCKOPS_WRAPPED
(
ax25_proto_ops
)
=
{
static
struct
proto_ops
ax25_proto_ops
=
{
.
family
=
PF_AX25
,
.
release
=
ax25_release
,
...
...
@@ -1835,15 +1935,14 @@ static struct proto_ops SOCKOPS_WRAPPED(ax25_proto_ops) = {
.
sendpage
=
sock_no_sendpage
,
};
#include <linux/smp_lock.h>
SOCKOPS_WRAP
(
ax25_proto
,
PF_AX25
);
/*
* Called by socket.c on kernel start up
*/
static
struct
packet_type
ax25_packet_type
=
{
.
type
=
__constant_htons
(
ETH_P_AX25
),
.
dev
=
NULL
,
/* All devices */
.
func
=
ax25_kiss_rcv
,
.
data
=
(
void
*
)
1
};
static
struct
notifier_block
ax25_dev_notifier
=
{
...
...
net/ax25/ax25_addr.c
View file @
a4041f6f
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* AX.25 036 Jonathan(G4KLX) Split from ax25_subr.c.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
...
...
net/ax25/ax25_dev.c
View file @
a4041f6f
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Other kernels modules in this kit are generally BSD derived. See the copyright headers.
*
*
* History
* AX.25 036 Jonathan(G4KLX) Split from ax25_route.c.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
...
...
@@ -27,6 +17,7 @@
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/spinlock.h>
#include <net/ax25.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
...
...
@@ -41,27 +32,35 @@
#include <linux/init.h>
ax25_dev
*
ax25_dev_list
;
spinlock_t
ax25_dev_lock
=
SPIN_LOCK_UNLOCKED
;
ax25_dev
*
ax25_dev_ax25dev
(
struct
net_device
*
dev
)
{
ax25_dev
*
ax25_dev
;
ax25_dev
*
ax25_dev
,
*
res
=
NULL
;
spin_lock_bh
(
&
ax25_dev_lock
);
for
(
ax25_dev
=
ax25_dev_list
;
ax25_dev
!=
NULL
;
ax25_dev
=
ax25_dev
->
next
)
if
(
ax25_dev
->
dev
==
dev
)
return
ax25_dev
;
if
(
ax25_dev
->
dev
==
dev
)
{
res
=
ax25_dev
;
break
;
}
spin_unlock_bh
(
&
ax25_dev_lock
);
return
NULL
;
return
res
;
}
ax25_dev
*
ax25_addr_ax25dev
(
ax25_address
*
addr
)
{
ax25_dev
*
ax25_dev
;
ax25_dev
*
ax25_dev
,
*
res
=
NULL
;
spin_lock_bh
(
&
ax25_dev_lock
);
for
(
ax25_dev
=
ax25_dev_list
;
ax25_dev
!=
NULL
;
ax25_dev
=
ax25_dev
->
next
)
if
(
ax25cmp
(
addr
,
(
ax25_address
*
)
ax25_dev
->
dev
->
dev_addr
)
==
0
)
return
ax25_dev
;
if
(
ax25cmp
(
addr
,
(
ax25_address
*
)
ax25_dev
->
dev
->
dev_addr
)
==
0
)
{
res
=
ax25_dev
;
}
spin_unlock_bh
(
&
ax25_dev_lock
);
return
NULL
;
return
res
;
}
/*
...
...
@@ -71,7 +70,6 @@ ax25_dev *ax25_addr_ax25dev(ax25_address *addr)
void
ax25_dev_device_up
(
struct
net_device
*
dev
)
{
ax25_dev
*
ax25_dev
;
unsigned
long
flags
;
if
((
ax25_dev
=
kmalloc
(
sizeof
(
*
ax25_dev
),
GFP_ATOMIC
))
==
NULL
)
{
printk
(
KERN_ERR
"AX.25: ax25_dev_device_up - out of memory
\n
"
);
...
...
@@ -100,10 +98,10 @@ void ax25_dev_device_up(struct net_device *dev)
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
]
=
AX25_DEF_PROTOCOL
;
ax25_dev
->
values
[
AX25_VALUES_DS_TIMEOUT
]
=
AX25_DEF_DS_TIMEOUT
;
s
ave_flags
(
flags
);
cli
(
);
s
pin_lock_bh
(
&
ax25_dev_lock
);
ax25_dev
->
next
=
ax25_dev_list
;
ax25_dev_list
=
ax25_dev
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
ax25_dev_lock
);
ax25_register_sysctl
();
}
...
...
@@ -111,14 +109,13 @@ void ax25_dev_device_up(struct net_device *dev)
void
ax25_dev_device_down
(
struct
net_device
*
dev
)
{
ax25_dev
*
s
,
*
ax25_dev
;
unsigned
long
flags
;
if
((
ax25_dev
=
ax25_dev_ax25dev
(
dev
))
==
NULL
)
return
;
ax25_unregister_sysctl
();
s
ave_flags
(
flags
);
cli
(
);
s
pin_lock_bh
(
&
ax25_dev_lock
);
#ifdef CONFIG_AX25_DAMA_SLAVE
ax25_ds_del_timer
(
ax25_dev
);
...
...
@@ -133,7 +130,7 @@ void ax25_dev_device_down(struct net_device *dev)
if
((
s
=
ax25_dev_list
)
==
ax25_dev
)
{
ax25_dev_list
=
s
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
ax25_dev_lock
);
kfree
(
ax25_dev
);
ax25_register_sysctl
();
return
;
...
...
@@ -142,7 +139,7 @@ void ax25_dev_device_down(struct net_device *dev)
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
if
(
s
->
next
==
ax25_dev
)
{
s
->
next
=
ax25_dev
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
ax25_dev_lock
);
kfree
(
ax25_dev
);
ax25_register_sysctl
();
return
;
...
...
@@ -150,8 +147,8 @@ void ax25_dev_device_down(struct net_device *dev)
s
=
s
->
next
;
}
spin_unlock_bh
(
&
ax25_dev_lock
);
restore_flags
(
flags
);
ax25_register_sysctl
();
}
...
...
@@ -202,12 +199,16 @@ struct net_device *ax25_fwd_dev(struct net_device *dev)
*/
void
__exit
ax25_dev_free
(
void
)
{
ax25_dev
*
s
,
*
ax25_dev
=
ax25_dev_list
;
ax25_dev
*
s
,
*
ax25_dev
;
spin_lock_bh
(
&
ax25_dev_lock
);
ax25_dev
=
ax25_dev_list
;
while
(
ax25_dev
!=
NULL
)
{
s
=
ax25_dev
;
ax25_dev
=
ax25_dev
->
next
;
kfree
(
s
);
}
ax25_dev_list
=
NULL
;
spin_unlock_bh
(
&
ax25_dev_lock
);
}
net/ax25/ax25_ds_in.c
View file @
a4041f6f
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* AX.25 036 Jonathan(G4KLX) Cloned from ax25_in.c
* Joerg(DL1BKE) Fixed it.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Joerg(DL1BKE) ax25->n2count never got reset
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
...
...
@@ -95,11 +80,13 @@ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
break
;
case
AX25_DM
:
if
(
pf
)
ax25_disconnect
(
ax25
,
ECONNREFUSED
);
if
(
pf
)
ax25_disconnect
(
ax25
,
ECONNREFUSED
);
break
;
default:
if
(
pf
)
ax25_send_control
(
ax25
,
AX25_SABM
,
AX25_POLLON
,
AX25_COMMAND
);
if
(
pf
)
ax25_send_control
(
ax25
,
AX25_SABM
,
AX25_POLLON
,
AX25_COMMAND
);
break
;
}
...
...
net/ax25/ax25_ds_subr.c
View file @
a4041f6f
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* AX.25 036 Jonathan(G4KLX) Cloned from ax25_out.c and ax25_subr.c.
* Joerg(DL1BKE) Changed ax25_ds_enquiry_response(),
* fixed ax25_dama_on() and ax25_dama_off().
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
...
...
@@ -31,6 +16,7 @@
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/spinlock.h>
#include <linux/net.h>
#include <net/ax25.h>
#include <linux/inet.h>
...
...
@@ -93,6 +79,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
ax25_start_t3timer
(
ax25
);
ax25_ds_set_timer
(
ax25
->
ax25_dev
);
spin_lock_bh
(
&
ax25_list_lock
);
for
(
ax25o
=
ax25_list
;
ax25o
!=
NULL
;
ax25o
=
ax25o
->
next
)
{
if
(
ax25o
==
ax25
)
continue
;
...
...
@@ -118,6 +105,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
if
(
ax25o
->
state
!=
AX25_STATE_0
)
ax25_start_t3timer
(
ax25o
);
}
spin_unlock_bh
(
&
ax25_list_lock
);
}
void
ax25_ds_establish_data_link
(
ax25_cb
*
ax25
)
...
...
@@ -171,12 +159,17 @@ static void ax25_kiss_cmd(ax25_dev *ax25_dev, unsigned char cmd, unsigned char p
static
int
ax25_check_dama_slave
(
ax25_dev
*
ax25_dev
)
{
ax25_cb
*
ax25
;
int
res
=
0
;
spin_lock_bh
(
&
ax25_list_lock
);
for
(
ax25
=
ax25_list
;
ax25
!=
NULL
;
ax25
=
ax25
->
next
)
if
(
ax25
->
ax25_dev
==
ax25_dev
&&
(
ax25
->
condition
&
AX25_COND_DAMA_MODE
)
&&
ax25
->
state
>
AX25_STATE_1
)
return
1
;
if
(
ax25
->
ax25_dev
==
ax25_dev
&&
(
ax25
->
condition
&
AX25_COND_DAMA_MODE
)
&&
ax25
->
state
>
AX25_STATE_1
)
{
res
=
1
;
break
;
}
spin_unlock_bh
(
&
ax25_list_lock
);
return
0
;
return
res
;
}
void
ax25_dev_dama_on
(
ax25_dev
*
ax25_dev
)
...
...
net/ax25/ax25_ds_timer.c
View file @
a4041f6f
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* AX.25 036 Jonathan(G4KLX) Cloned from ax25_timer.c.
* Joerg(DL1BKE) Added DAMA Slave Timeout timer
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/spinlock.h>
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/jiffies.h>
...
...
@@ -58,7 +51,8 @@ static void ax25_ds_add_timer(ax25_dev *ax25_dev)
void
ax25_ds_del_timer
(
ax25_dev
*
ax25_dev
)
{
if
(
ax25_dev
)
del_timer
(
&
ax25_dev
->
dama
.
slave_timer
);
if
(
ax25_dev
)
del_timer
(
&
ax25_dev
->
dama
.
slave_timer
);
}
void
ax25_ds_set_timer
(
ax25_dev
*
ax25_dev
)
...
...
@@ -89,6 +83,7 @@ static void ax25_ds_timeout(unsigned long arg)
return
;
}
spin_lock_bh
(
&
ax25_list_lock
);
for
(
ax25
=
ax25_list
;
ax25
!=
NULL
;
ax25
=
ax25
->
next
)
{
if
(
ax25
->
ax25_dev
!=
ax25_dev
||
!
(
ax25
->
condition
&
AX25_COND_DAMA_MODE
))
continue
;
...
...
@@ -96,6 +91,7 @@ static void ax25_ds_timeout(unsigned long arg)
ax25_send_control
(
ax25
,
AX25_DISC
,
AX25_POLLON
,
AX25_COMMAND
);
ax25_disconnect
(
ax25
,
ETIMEDOUT
);
}
spin_unlock_bh
(
&
ax25_list_lock
);
ax25_dev_dama_off
(
ax25_dev
);
}
...
...
@@ -178,7 +174,6 @@ void ax25_ds_idletimer_expiry(ax25_cb *ax25)
void
ax25_ds_t1_timeout
(
ax25_cb
*
ax25
)
{
switch
(
ax25
->
state
)
{
case
AX25_STATE_1
:
if
(
ax25
->
n2count
==
ax25
->
n2
)
{
if
(
ax25
->
modulus
==
AX25_MODULUS
)
{
...
...
net/ax25/ax25_iface.c
View file @
a4041f6f
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* AX.25 036 Jonathan(G4KLX) Split from ax25_timer.c.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
...
...
@@ -20,6 +13,7 @@
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/sockios.h>
...
...
@@ -40,22 +34,25 @@ static struct protocol_struct {
unsigned
int
pid
;
int
(
*
func
)(
struct
sk_buff
*
,
ax25_cb
*
);
}
*
protocol_list
;
static
rwlock_t
protocol_list_lock
=
RW_LOCK_UNLOCKED
;
static
struct
linkfail_struct
{
struct
linkfail_struct
*
next
;
void
(
*
func
)(
ax25_cb
*
,
int
);
}
*
linkfail_list
;
static
spinlock_t
linkfail_lock
=
SPIN_LOCK_UNLOCKED
;
static
struct
listen_struct
{
struct
listen_struct
*
next
;
ax25_address
callsign
;
struct
net_device
*
dev
;
}
*
listen_list
;
static
spinlock_t
listen_lock
=
SPIN_LOCK_UNLOCKED
;
int
ax25_protocol_register
(
unsigned
int
pid
,
int
(
*
func
)(
struct
sk_buff
*
,
ax25_cb
*
))
int
ax25_protocol_register
(
unsigned
int
pid
,
int
(
*
func
)(
struct
sk_buff
*
,
ax25_cb
*
))
{
struct
protocol_struct
*
protocol
;
unsigned
long
flags
;
if
(
pid
==
AX25_P_TEXT
||
pid
==
AX25_P_SEGMENT
)
return
0
;
...
...
@@ -69,31 +66,28 @@ int ax25_protocol_register(unsigned int pid, int (*func)(struct sk_buff *, ax25_
protocol
->
pid
=
pid
;
protocol
->
func
=
func
;
save_flags
(
flags
);
cli
();
write_lock
(
&
protocol_list_lock
);
protocol
->
next
=
protocol_list
;
protocol_list
=
protocol
;
restore_flags
(
flags
);
write_unlock
(
&
protocol_list_lock
);
return
1
;
}
void
ax25_protocol_release
(
unsigned
int
pid
)
{
struct
protocol_struct
*
s
,
*
protocol
=
protocol_list
;
unsigned
long
flags
;
struct
protocol_struct
*
s
,
*
protocol
;
if
(
protocol
==
NULL
)
write_lock
(
&
protocol_list_lock
);
protocol
=
protocol_list
;
if
(
protocol
==
NULL
)
{
write_unlock
(
&
protocol_list_lock
);
return
;
save_flags
(
flags
);
cli
();
}
if
(
protocol
->
pid
==
pid
)
{
protocol_list
=
protocol
->
next
;
restore_flags
(
flags
);
write_unlock
(
&
protocol_list_lock
);
kfree
(
protocol
);
return
;
}
...
...
@@ -102,52 +96,45 @@ void ax25_protocol_release(unsigned int pid)
if
(
protocol
->
next
->
pid
==
pid
)
{
s
=
protocol
->
next
;
protocol
->
next
=
protocol
->
next
->
next
;
restore_flags
(
flags
);
write_unlock
(
&
protocol_list_lock
);
kfree
(
s
);
return
;
}
protocol
=
protocol
->
next
;
}
restore_flags
(
flags
);
write_unlock
(
&
protocol_list_lock
);
}
int
ax25_linkfail_register
(
void
(
*
func
)(
ax25_cb
*
,
int
))
{
struct
linkfail_struct
*
linkfail
;
unsigned
long
flags
;
if
((
linkfail
=
kmalloc
(
sizeof
(
*
linkfail
),
GFP_ATOMIC
))
==
NULL
)
return
0
;
linkfail
->
func
=
func
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
linkfail_lock
);
linkfail
->
next
=
linkfail_list
;
linkfail_list
=
linkfail
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
linkfail_lock
);
return
1
;
}
void
ax25_linkfail_release
(
void
(
*
func
)(
ax25_cb
*
,
int
))
{
struct
linkfail_struct
*
s
,
*
linkfail
=
linkfail_list
;
unsigned
long
flags
;
struct
linkfail_struct
*
s
,
*
linkfail
;
spin_lock_bh
(
&
linkfail_lock
);
linkfail
=
linkfail_list
;
if
(
linkfail
==
NULL
)
return
;
save_flags
(
flags
);
cli
();
if
(
linkfail
->
func
==
func
)
{
linkfail_list
=
linkfail
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
linkfail_lock
);
kfree
(
linkfail
);
return
;
}
...
...
@@ -156,21 +143,19 @@ void ax25_linkfail_release(void (*func)(ax25_cb *, int))
if
(
linkfail
->
next
->
func
==
func
)
{
s
=
linkfail
->
next
;
linkfail
->
next
=
linkfail
->
next
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
linkfail_lock
);
kfree
(
s
);
return
;
}
linkfail
=
linkfail
->
next
;
}
restore_flags
(
flags
);
spin_unlock_bh
(
&
linkfail_lock
);
}
int
ax25_listen_register
(
ax25_address
*
callsign
,
struct
net_device
*
dev
)
{
struct
listen_struct
*
listen
;
unsigned
long
flags
;
if
(
ax25_listen_mine
(
callsign
,
dev
))
return
0
;
...
...
@@ -181,31 +166,26 @@ int ax25_listen_register(ax25_address *callsign, struct net_device *dev)
listen
->
callsign
=
*
callsign
;
listen
->
dev
=
dev
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
listen_lock
);
listen
->
next
=
listen_list
;
listen_list
=
listen
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
listen_lock
);
return
1
;
}
void
ax25_listen_release
(
ax25_address
*
callsign
,
struct
net_device
*
dev
)
{
struct
listen_struct
*
s
,
*
listen
=
listen_list
;
unsigned
long
flags
;
struct
listen_struct
*
s
,
*
listen
;
spin_lock_bh
(
&
listen_lock
);
listen
=
listen_list
;
if
(
listen
==
NULL
)
return
;
save_flags
(
flags
);
cli
();
if
(
ax25cmp
(
&
listen
->
callsign
,
callsign
)
==
0
&&
listen
->
dev
==
dev
)
{
listen_list
=
listen
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
listen_lock
);
kfree
(
listen
);
return
;
}
...
...
@@ -214,35 +194,41 @@ void ax25_listen_release(ax25_address *callsign, struct net_device *dev)
if
(
ax25cmp
(
&
listen
->
next
->
callsign
,
callsign
)
==
0
&&
listen
->
next
->
dev
==
dev
)
{
s
=
listen
->
next
;
listen
->
next
=
listen
->
next
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
listen_lock
);
kfree
(
s
);
return
;
}
listen
=
listen
->
next
;
}
restore_flags
(
flags
);
spin_unlock_bh
(
&
listen_lock
);
}
int
(
*
ax25_protocol_function
(
unsigned
int
pid
))(
struct
sk_buff
*
,
ax25_cb
*
)
{
int
(
*
res
)(
struct
sk_buff
*
,
ax25_cb
*
)
=
NULL
;
struct
protocol_struct
*
protocol
;
read_lock
(
&
protocol_list_lock
);
for
(
protocol
=
protocol_list
;
protocol
!=
NULL
;
protocol
=
protocol
->
next
)
if
(
protocol
->
pid
==
pid
)
return
protocol
->
func
;
if
(
protocol
->
pid
==
pid
)
{
res
=
protocol
->
func
;
break
;
}
read_unlock
(
&
protocol_list_lock
);
return
NULL
;
return
res
;
}
int
ax25_listen_mine
(
ax25_address
*
callsign
,
struct
net_device
*
dev
)
{
struct
listen_struct
*
listen
;
spin_lock_bh
(
&
listen_lock
);
for
(
listen
=
listen_list
;
listen
!=
NULL
;
listen
=
listen
->
next
)
if
(
ax25cmp
(
&
listen
->
callsign
,
callsign
)
==
0
&&
(
listen
->
dev
==
dev
||
listen
->
dev
==
NULL
))
return
1
;
spin_unlock_bh
(
&
listen_lock
);
return
0
;
}
...
...
@@ -251,18 +237,24 @@ void ax25_link_failed(ax25_cb *ax25, int reason)
{
struct
linkfail_struct
*
linkfail
;
spin_lock_bh
(
&
linkfail_lock
);
for
(
linkfail
=
linkfail_list
;
linkfail
!=
NULL
;
linkfail
=
linkfail
->
next
)
(
linkfail
->
func
)(
ax25
,
reason
);
spin_unlock_bh
(
&
linkfail_lock
);
}
int
ax25_protocol_is_registered
(
unsigned
int
pid
)
{
struct
protocol_struct
*
protocol
;
int
res
=
0
;
read_lock
(
&
protocol_list_lock
);
for
(
protocol
=
protocol_list
;
protocol
!=
NULL
;
protocol
=
protocol
->
next
)
if
(
protocol
->
pid
==
pid
)
return
1
;
if
(
protocol
->
pid
==
pid
)
{
res
=
1
;
break
;
}
read_unlock
(
&
protocol_list_lock
);
return
0
;
return
res
;
}
net/ax25/ax25_in.c
View file @
a4041f6f
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams.
* AX.25 028b Jonathan(G4KLX) Extracted AX25 control block from
* the sock structure.
* AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names.
* Jonathan(G4KLX) Added IP mode registration.
* AX.25 030 Jonathan(G4KLX) Added AX.25 fragment reception.
* Upgraded state machine for SABME.
* Added arbitrary protocol id support.
* AX.25 031 Joerg(DL1BKE) Added DAMA support
* HaJo(DD8NE) Added Idle Disc Timer T5
* Joerg(DL1BKE) Renamed it to "IDLE" with a slightly
* different behaviour. Fixed defrag
* routine (I hope)
* AX.25 032 Darryl(G7LED) AX.25 segmentation fixed.
* AX.25 033 Jonathan(G4KLX) Remove auto-router.
* Modularisation changes.
* AX.25 035 Hans(PE1AYX) Fixed interface to IP layer.
* AX.25 036 Jonathan(G4KLX) Move DAMA code into own file.
* Joerg(DL1BKE) Fixed DAMA Slave.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Thomas(DL9SAU) Fixed missing initialization of skb->protocol.
* Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
*/
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
...
...
@@ -217,19 +187,15 @@ static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, i
return
queued
;
}
static
int
ax25_rcv
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
,
ax25_address
*
dev_addr
,
struct
packet_type
*
ptype
)
static
int
ax25_rcv
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
,
ax25_address
*
dev_addr
,
struct
packet_type
*
ptype
)
{
struct
sock
*
make
;
struct
sock
*
sk
;
int
type
=
0
;
ax25_address
src
,
dest
,
*
next_digi
=
NULL
;
int
type
=
0
,
mine
=
0
,
dama
;
struct
sock
*
make
,
*
sk
,
*
raw
;
ax25_digi
dp
,
reverse_dp
;
ax25_cb
*
ax25
;
ax25_address
src
,
dest
;
ax25_address
*
next_digi
=
NULL
;
ax25_dev
*
ax25_dev
;
struct
sock
*
raw
;
int
mine
=
0
;
int
dama
;
/*
* Process the AX.25/LAPB frame.
...
...
@@ -274,8 +240,10 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d
if
((
*
skb
->
data
&
~
0x10
)
==
AX25_UI
&&
dp
.
lastrepeat
+
1
==
dp
.
ndigi
)
{
skb
->
h
.
raw
=
skb
->
data
+
2
;
/* skip control and pid */
if
((
raw
=
ax25_addr_match
(
&
dest
))
!=
NULL
)
if
((
raw
=
ax25_addr_match
(
&
dest
))
!=
NULL
)
{
ax25_send_to_raw
(
raw
,
skb
,
skb
->
data
[
1
]);
release_sock
(
raw
);
}
if
(
!
mine
&&
ax25cmp
(
&
dest
,
(
ax25_address
*
)
dev
->
broadcast
)
!=
0
)
{
kfree_skb
(
skb
);
...
...
@@ -307,7 +275,8 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d
#endif
case
AX25_P_TEXT
:
/* Now find a suitable dgram socket */
if
((
sk
=
ax25_find_socket
(
&
dest
,
&
src
,
SOCK_DGRAM
))
!=
NULL
)
{
sk
=
ax25_get_socket
(
&
dest
,
&
src
,
SOCK_DGRAM
);
if
(
sk
!=
NULL
)
{
if
(
atomic_read
(
&
sk
->
rmem_alloc
)
>=
sk
->
rcvbuf
)
{
kfree_skb
(
skb
);
}
else
{
...
...
@@ -318,6 +287,7 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d
if
(
sock_queue_rcv_skb
(
sk
,
skb
)
!=
0
)
kfree_skb
(
skb
);
}
release_sock
(
sk
);
}
else
{
kfree_skb
(
skb
);
}
...
...
@@ -349,9 +319,10 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d
if
((
ax25
=
ax25_find_cb
(
&
dest
,
&
src
,
&
reverse_dp
,
dev
))
!=
NULL
)
{
/*
* Process the frame. If it is queued up internally it returns one otherwise we
* free it immediately. This routine itself wakes the user context layers so we
* do no further work
* Process the frame. If it is queued up internally it
* returns one otherwise we free it immediately. This
* routine itself wakes the user context layers so we do
* no further work
*/
if
(
ax25_process_rx_frame
(
ax25
,
skb
,
type
,
dama
)
==
0
)
kfree_skb
(
skb
);
...
...
@@ -363,7 +334,8 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d
/* a) received not a SABM(E) */
if
((
*
skb
->
data
&
~
AX25_PF
)
!=
AX25_SABM
&&
(
*
skb
->
data
&
~
AX25_PF
)
!=
AX25_SABME
)
{
if
((
*
skb
->
data
&
~
AX25_PF
)
!=
AX25_SABM
&&
(
*
skb
->
data
&
~
AX25_PF
)
!=
AX25_SABME
)
{
/*
* Never reply to a DM. Also ignore any connects for
* addresses that are not our interfaces and not a socket.
...
...
@@ -383,9 +355,12 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d
sk
=
ax25_find_listener
(
next_digi
,
1
,
dev
,
SOCK_SEQPACKET
);
if
(
sk
!=
NULL
)
{
if
(
sk
->
ack_backlog
==
sk
->
max_ack_backlog
||
(
make
=
ax25_make_new
(
sk
,
ax25_dev
))
==
NULL
)
{
if
(
mine
)
ax25_return_dm
(
dev
,
&
src
,
&
dest
,
&
dp
);
if
(
sk
->
ack_backlog
==
sk
->
max_ack_backlog
||
(
make
=
ax25_make_new
(
sk
,
ax25_dev
))
==
NULL
)
{
if
(
mine
)
ax25_return_dm
(
dev
,
&
src
,
&
dest
,
&
dp
);
kfree_skb
(
skb
);
return
0
;
}
...
...
@@ -486,4 +461,3 @@ int ax25_kiss_rcv(struct sk_buff *skb, struct net_device *dev,
return
ax25_rcv
(
skb
,
dev
,
(
ax25_address
*
)
dev
->
dev_addr
,
ptype
);
}
net/ax25/ax25_ip.c
View file @
a4041f6f
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* AX.25 036 Jonathan(G4KLX) Split from af_ax25.c.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
...
...
@@ -112,8 +105,8 @@ int ax25_rebuild_header(struct sk_buff *skb)
unsigned
char
*
bp
=
skb
->
data
;
struct
net_device
*
dev
;
ax25_address
*
src
,
*
dst
;
ax25_route
*
route
;
ax25_dev
*
ax25_dev
;
ax25_route
_route
,
*
route
=
&
_route
;
dst
=
(
ax25_address
*
)(
bp
+
1
);
src
=
(
ax25_address
*
)(
bp
+
8
);
...
...
@@ -121,14 +114,15 @@ int ax25_rebuild_header(struct sk_buff *skb)
if
(
arp_find
(
bp
+
1
,
skb
))
return
1
;
route
=
ax25_rt_find_route
(
dst
,
NULL
);
route
=
ax25_rt_find_route
(
route
,
dst
,
NULL
);
dev
=
route
->
dev
;
if
(
dev
==
NULL
)
dev
=
skb
->
dev
;
if
((
ax25_dev
=
ax25_dev_ax25dev
(
dev
))
==
NULL
)
return
1
;
if
((
ax25_dev
=
ax25_dev_ax25dev
(
dev
))
==
NULL
)
{
goto
put
;
}
if
(
bp
[
16
]
==
AX25_P_IP
)
{
if
(
route
->
ip_mode
==
'V'
||
(
route
->
ip_mode
==
' '
&&
ax25_dev
->
values
[
AX25_VALUES_IPDEFMODE
]))
{
...
...
@@ -153,7 +147,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
if
((
ourskb
=
skb_copy
(
skb
,
GFP_ATOMIC
))
==
NULL
)
{
kfree_skb
(
skb
);
return
1
;
goto
put
;
}
if
(
skb
->
sk
!=
NULL
)
...
...
@@ -170,7 +164,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
ax25_send_frame
(
ourskb
,
ax25_dev
->
values
[
AX25_VALUES_PACLEN
],
&
src_c
,
&
dst_c
,
route
->
digipeat
,
dev
);
return
1
;
goto
put
;
}
}
...
...
@@ -187,7 +181,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
if
(
route
->
digipeat
!=
NULL
)
{
if
((
ourskb
=
ax25_rt_build_path
(
skb
,
src
,
dst
,
route
->
digipeat
))
==
NULL
)
{
kfree_skb
(
skb
);
return
1
;
goto
put
;
}
skb
=
ourskb
;
...
...
@@ -197,6 +191,9 @@ int ax25_rebuild_header(struct sk_buff *skb)
ax25_queue_xmit
(
skb
);
put:
ax25_put_route
(
route
);
return
1
;
}
...
...
net/ax25/ax25_out.c
View file @
a4041f6f
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams.
* AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names.
* Jonathan(G4KLX) Only poll when window is full.
* AX.25 030 Jonathan(G4KLX) Added fragmentation to ax25_output.
* Added support for extended AX.25.
* AX.25 031 Joerg(DL1BKE) Added DAMA support
* Joerg(DL1BKE) Modified fragmenter to fragment vanilla
* AX.25 I-Frames. Added PACLEN parameter.
* Joerg(DL1BKE) Fixed a problem with buffer allocation
* for fragments.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Joerg(DL1BKE) Fixed DAMA Slave mode: will work
* on non-DAMA interfaces like AX25L2V2
* again (this behaviour is _required_).
* Joerg(DL1BKE) ax25_check_iframes_acked() returns a
* value now (for DAMA n2count handling)
* Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
*/
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
...
...
@@ -44,6 +18,7 @@
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/spinlock.h>
#include <linux/net.h>
#include <net/ax25.h>
#include <linux/inet.h>
...
...
@@ -57,6 +32,8 @@
#include <linux/mm.h>
#include <linux/interrupt.h>
static
spinlock_t
ax25_frag_lock
=
SPIN_LOCK_UNLOCKED
;
ax25_cb
*
ax25_send_frame
(
struct
sk_buff
*
skb
,
int
paclen
,
ax25_address
*
src
,
ax25_address
*
dest
,
ax25_digi
*
digi
,
struct
net_device
*
dev
)
{
ax25_dev
*
ax25_dev
;
...
...
@@ -138,7 +115,6 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
struct
sk_buff
*
skbn
;
unsigned
char
*
p
;
int
frontlen
,
len
,
fragno
,
ka9qfrag
,
first
=
1
;
long
flags
;
if
((
skb
->
len
-
1
)
>
paclen
)
{
if
(
*
skb
->
data
==
AX25_P_TEXT
)
{
...
...
@@ -155,11 +131,9 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
frontlen
=
skb_headroom
(
skb
);
/* Address space + CTRL */
while
(
skb
->
len
>
0
)
{
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
ax25_frag_lock
);
if
((
skbn
=
alloc_skb
(
paclen
+
2
+
frontlen
,
GFP_ATOMIC
))
==
NULL
)
{
restore_flags
(
flags
);
spin_unlock_bh
(
&
ax25_frag_lock
);
printk
(
KERN_CRIT
"AX.25: ax25_output - out of memory
\n
"
);
return
;
}
...
...
@@ -167,7 +141,7 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
if
(
skb
->
sk
!=
NULL
)
skb_set_owner_w
(
skbn
,
skb
->
sk
);
restore_flags
(
flags
);
spin_unlock_bh
(
&
ax25_frag_lock
);
len
=
(
paclen
>
skb
->
len
)
?
skb
->
len
:
paclen
;
...
...
net/ax25/ax25_route.c
View file @
a4041f6f
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Other kernels modules in this kit are generally BSD derived. See the copyright headers.
*
*
* History
* AX.25 020 Jonathan(G4KLX) First go.
* AX.25 022 Jonathan(G4KLX) Added the actual meat to this - we now have a nice heard list.
* AX.25 025 Alan(GW4PTS) First cut at autobinding by route scan.
* AX.25 028b Jonathan(G4KLX) Extracted AX25 control block from the
* sock structure. Device removal now
* removes the heard structure.
* AX.25 029 Steven(GW7RRM) Added /proc information for uid/callsign mapping.
* Jonathan(G4KLX) Handling of IP mode in the routing list and /proc entry.
* AX.25 030 Jonathan(G4KLX) Added digi-peaters to routing table, and
* ioctls to manipulate them. Added port
* configuration.
* AX.25 031 Jonathan(G4KLX) Added concept of default route.
* Joerg(DL1BKE) ax25_rt_build_path() find digipeater list and device by
* destination call. Needed for IP routing via digipeater
* Jonathan(G4KLX) Added routing for IP datagram packets.
* Joerg(DL1BKE) Changed routing for IP datagram and VC to use a default
* route if available. Does not overwrite default routes
* on route-table overflow anymore.
* Joerg(DL1BKE) Fixed AX.25 routing of IP datagram and VC, new ioctl()
* "SIOCAX25OPTRT" to set IP mode and a 'permanent' flag
* on routes.
* AX.25 033 Jonathan(G4KLX) Remove auto-router.
* Joerg(DL1BKE) Moved BPQ Ethernet driver to separate device.
* AX.25 035 Frederic(F1OAT) Support for pseudo-digipeating.
* Jonathan(G4KLX) Support for packet forwarding.
* Arnaldo C. Melo s/suser/capable/
* Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Steven Whitehouse GW7RRM (stevew@acm.org)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
* Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/timer.h>
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/sched.h>
...
...
@@ -56,6 +27,7 @@
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <net/sock.h>
#include <asm/uaccess.h>
#include <asm/system.h>
...
...
@@ -65,8 +37,9 @@
#include <linux/init.h>
static
ax25_route
*
ax25_route_list
;
static
rwlock_t
ax25_route_lock
=
RW_LOCK_UNLOCKED
;
static
ax25_route
*
ax25_
find
_route
(
ax25_address
*
,
struct
net_device
*
);
static
ax25_route
*
ax25_
get
_route
(
ax25_address
*
,
struct
net_device
*
);
/*
* small macro to drop non-digipeated digipeaters and reverse path
...
...
@@ -86,8 +59,10 @@ static inline void ax25_route_invert(ax25_digi *in, ax25_digi *out)
void
ax25_rt_device_down
(
struct
net_device
*
dev
)
{
ax25_route
*
s
,
*
t
,
*
ax25_rt
=
ax25_route_list
;
ax25_route
*
s
,
*
t
,
*
ax25_rt
;
write_lock
(
&
ax25_route_lock
);
ax25_rt
=
ax25_route_list
;
while
(
ax25_rt
!=
NULL
)
{
s
=
ax25_rt
;
ax25_rt
=
ax25_rt
->
next
;
...
...
@@ -111,129 +86,196 @@ void ax25_rt_device_down(struct net_device *dev)
}
}
}
write_unlock
(
&
ax25_route_lock
);
}
int
ax25_rt_ioctl
(
unsigned
int
cmd
,
void
*
arg
)
static
int
ax25_rt_add
(
struct
ax25_routes_struct
*
route
)
{
unsigned
long
flags
;
ax25_route
*
s
,
*
t
,
*
ax25_rt
;
struct
ax25_routes_struct
route
;
struct
ax25_route_opt_struct
rt_option
;
ax25_route
*
ax25_rt
;
ax25_dev
*
ax25_dev
;
int
i
;
switch
(
cmd
)
{
case
SIOCADDRT
:
if
(
copy_from_user
(
&
route
,
arg
,
sizeof
(
route
)))
return
-
EFAULT
;
if
((
ax25_dev
=
ax25_addr_ax25dev
(
&
route
.
port_addr
))
==
NULL
)
if
((
ax25_dev
=
ax25_addr_ax25dev
(
&
route
->
port_addr
))
==
NULL
)
return
-
EINVAL
;
if
(
route
.
digi_count
>
AX25_MAX_DIGIS
)
if
(
route
->
digi_count
>
AX25_MAX_DIGIS
)
return
-
EINVAL
;
for
(
ax25_rt
=
ax25_route_list
;
ax25_rt
!=
NULL
;
ax25_rt
=
ax25_rt
->
next
)
{
if
(
ax25cmp
(
&
ax25_rt
->
callsign
,
&
route
.
dest_addr
)
==
0
&&
ax25_rt
->
dev
==
ax25_dev
->
dev
)
{
write_lock
(
&
ax25_route_lock
);
ax25_rt
=
ax25_route_list
;
while
(
ax25_rt
!=
NULL
)
{
if
(
ax25cmp
(
&
ax25_rt
->
callsign
,
&
route
->
dest_addr
)
==
0
&&
ax25_rt
->
dev
==
ax25_dev
->
dev
)
{
if
(
ax25_rt
->
digipeat
!=
NULL
)
{
kfree
(
ax25_rt
->
digipeat
);
ax25_rt
->
digipeat
=
NULL
;
}
if
(
route
.
digi_count
!=
0
)
{
if
((
ax25_rt
->
digipeat
=
kmalloc
(
sizeof
(
ax25_digi
),
GFP_ATOMIC
))
==
NULL
)
if
(
route
->
digi_count
!=
0
)
{
if
((
ax25_rt
->
digipeat
=
kmalloc
(
sizeof
(
ax25_digi
),
GFP_ATOMIC
))
==
NULL
)
{
write_unlock
(
&
ax25_route_lock
);
return
-
ENOMEM
;
}
ax25_rt
->
digipeat
->
lastrepeat
=
-
1
;
ax25_rt
->
digipeat
->
ndigi
=
route
.
digi_count
;
for
(
i
=
0
;
i
<
route
.
digi_count
;
i
++
)
{
ax25_rt
->
digipeat
->
ndigi
=
route
->
digi_count
;
for
(
i
=
0
;
i
<
route
->
digi_count
;
i
++
)
{
ax25_rt
->
digipeat
->
repeated
[
i
]
=
0
;
ax25_rt
->
digipeat
->
calls
[
i
]
=
route
.
digi_addr
[
i
];
ax25_rt
->
digipeat
->
calls
[
i
]
=
route
->
digi_addr
[
i
];
}
}
return
0
;
}
ax25_rt
=
ax25_rt
->
next
;
}
if
((
ax25_rt
=
kmalloc
(
sizeof
(
ax25_route
),
GFP_ATOMIC
))
==
NULL
)
if
((
ax25_rt
=
kmalloc
(
sizeof
(
ax25_route
),
GFP_ATOMIC
))
==
NULL
)
{
write_unlock
(
&
ax25_route_lock
);
return
-
ENOMEM
;
ax25_rt
->
callsign
=
route
.
dest_addr
;
}
atomic_set
(
&
ax25_rt
->
ref
,
0
);
ax25_rt
->
callsign
=
route
->
dest_addr
;
ax25_rt
->
dev
=
ax25_dev
->
dev
;
ax25_rt
->
digipeat
=
NULL
;
ax25_rt
->
ip_mode
=
' '
;
if
(
route
.
digi_count
!=
0
)
{
if
(
route
->
digi_count
!=
0
)
{
if
((
ax25_rt
->
digipeat
=
kmalloc
(
sizeof
(
ax25_digi
),
GFP_ATOMIC
))
==
NULL
)
{
write_unlock
(
&
ax25_route_lock
);
kfree
(
ax25_rt
);
return
-
ENOMEM
;
}
ax25_rt
->
digipeat
->
lastrepeat
=
-
1
;
ax25_rt
->
digipeat
->
ndigi
=
route
.
digi_count
;
for
(
i
=
0
;
i
<
route
.
digi_count
;
i
++
)
{
ax25_rt
->
digipeat
->
ndigi
=
route
->
digi_count
;
for
(
i
=
0
;
i
<
route
->
digi_count
;
i
++
)
{
ax25_rt
->
digipeat
->
repeated
[
i
]
=
0
;
ax25_rt
->
digipeat
->
calls
[
i
]
=
route
.
digi_addr
[
i
];
ax25_rt
->
digipeat
->
calls
[
i
]
=
route
->
digi_addr
[
i
];
}
}
save_flags
(
flags
);
cli
();
ax25_rt
->
next
=
ax25_route_list
;
ax25_route_list
=
ax25_rt
;
restore_flags
(
flags
);
break
;
write_unlock
(
&
ax25_route_lock
);
case
SIOCDELRT
:
if
(
copy_from_user
(
&
route
,
arg
,
sizeof
(
route
)))
return
-
EFAULT
;
if
((
ax25_dev
=
ax25_addr_ax25dev
(
&
route
.
port_addr
))
==
NULL
)
return
0
;
}
static
void
ax25_rt_destroy
(
ax25_route
*
ax25_rt
)
{
if
(
atomic_read
(
&
ax25_rt
->
ref
)
==
0
)
{
if
(
ax25_rt
->
digipeat
!=
NULL
)
kfree
(
ax25_rt
->
digipeat
);
kfree
(
ax25_rt
);
}
/*
* Uh... Route is still in use; we can't yet destroy it. Retry later.
*/
init_timer
(
&
ax25_rt
->
timer
);
ax25_rt
->
timer
.
data
=
(
unsigned
long
)
ax25_rt
;
ax25_rt
->
timer
.
function
=
(
void
*
)
ax25_rt_destroy
;
ax25_rt
->
timer
.
expires
=
jiffies
+
5
*
HZ
;
add_timer
(
&
ax25_rt
->
timer
);
}
static
int
ax25_rt_del
(
struct
ax25_routes_struct
*
route
)
{
ax25_route
*
s
,
*
t
,
*
ax25_rt
;
ax25_dev
*
ax25_dev
;
if
((
ax25_dev
=
ax25_addr_ax25dev
(
&
route
->
port_addr
))
==
NULL
)
return
-
EINVAL
;
write_lock
(
&
ax25_route_lock
);
ax25_rt
=
ax25_route_list
;
while
(
ax25_rt
!=
NULL
)
{
s
=
ax25_rt
;
ax25_rt
=
ax25_rt
->
next
;
if
(
s
->
dev
==
ax25_dev
->
dev
&&
ax25cmp
(
&
route
.
dest_addr
,
&
s
->
callsign
)
==
0
)
{
if
(
s
->
dev
==
ax25_dev
->
dev
&&
ax25cmp
(
&
route
->
dest_addr
,
&
s
->
callsign
)
==
0
)
{
if
(
ax25_route_list
==
s
)
{
ax25_route_list
=
s
->
next
;
if
(
s
->
digipeat
!=
NULL
)
kfree
(
s
->
digipeat
);
kfree
(
s
);
ax25_rt_destroy
(
s
);
}
else
{
for
(
t
=
ax25_route_list
;
t
!=
NULL
;
t
=
t
->
next
)
{
if
(
t
->
next
==
s
)
{
t
->
next
=
s
->
next
;
if
(
s
->
digipeat
!=
NULL
)
kfree
(
s
->
digipeat
);
kfree
(
s
);
ax25_rt_destroy
(
s
);
break
;
}
}
}
}
}
break
;
write_unlock
(
&
ax25_route_lock
)
;
case
SIOCAX25OPTRT
:
if
(
copy_from_user
(
&
rt_option
,
arg
,
sizeof
(
rt_option
)))
return
-
EFAULT
;
if
((
ax25_dev
=
ax25_addr_ax25dev
(
&
rt_option
.
port_addr
))
==
NULL
)
return
0
;
}
static
int
ax25_rt_opt
(
struct
ax25_route_opt_struct
*
rt_option
)
{
ax25_route
*
ax25_rt
;
ax25_dev
*
ax25_dev
;
int
err
=
0
;
if
((
ax25_dev
=
ax25_addr_ax25dev
(
&
rt_option
->
port_addr
))
==
NULL
)
return
-
EINVAL
;
for
(
ax25_rt
=
ax25_route_list
;
ax25_rt
!=
NULL
;
ax25_rt
=
ax25_rt
->
next
)
{
if
(
ax25_rt
->
dev
==
ax25_dev
->
dev
&&
ax25cmp
(
&
rt_option
.
dest_addr
,
&
ax25_rt
->
callsign
)
==
0
)
{
switch
(
rt_option
.
cmd
)
{
write_lock
(
&
ax25_route_lock
);
ax25_rt
=
ax25_route_list
;
while
(
ax25_rt
!=
NULL
)
{
if
(
ax25_rt
->
dev
==
ax25_dev
->
dev
&&
ax25cmp
(
&
rt_option
->
dest_addr
,
&
ax25_rt
->
callsign
)
==
0
)
{
switch
(
rt_option
->
cmd
)
{
case
AX25_SET_RT_IPMODE
:
switch
(
rt_option
.
arg
)
{
switch
(
rt_option
->
arg
)
{
case
' '
:
case
'D'
:
case
'V'
:
ax25_rt
->
ip_mode
=
rt_option
.
arg
;
ax25_rt
->
ip_mode
=
rt_option
->
arg
;
break
;
default:
return
-
EINVAL
;
err
=
-
EINVAL
;
goto
out
;
}
break
;
default:
return
-
EINVAL
;
err
=
-
EINVAL
;
goto
out
;
}
}
ax25_rt
=
ax25_rt
->
next
;
}
break
;
out:
write_unlock
(
&
ax25_route_lock
);
return
err
;
}
int
ax25_rt_ioctl
(
unsigned
int
cmd
,
void
*
arg
)
{
struct
ax25_route_opt_struct
rt_option
;
struct
ax25_routes_struct
route
;
switch
(
cmd
)
{
case
SIOCADDRT
:
if
(
copy_from_user
(
&
route
,
arg
,
sizeof
(
route
)))
return
-
EFAULT
;
return
ax25_rt_add
(
&
route
);
case
SIOCDELRT
:
if
(
copy_from_user
(
&
route
,
arg
,
sizeof
(
route
)))
return
-
EFAULT
;
return
ax25_rt_del
(
&
route
);
case
SIOCAX25OPTRT
:
if
(
copy_from_user
(
&
rt_option
,
arg
,
sizeof
(
rt_option
)))
return
-
EFAULT
;
return
ax25_rt_opt
(
&
rt_option
);
default:
return
-
EINVAL
;
}
return
0
;
}
int
ax25_rt_get_info
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
...
...
@@ -245,7 +287,7 @@ int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
char
*
callsign
;
int
i
;
cli
(
);
read_lock
(
&
ax25_route_lock
);
len
+=
sprintf
(
buffer
,
"callsign dev mode digipeaters
\n
"
);
...
...
@@ -286,26 +328,29 @@ int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
if
(
pos
>
offset
+
length
)
break
;
}
sti
();
read_unlock
(
&
ax25_route_lock
);
*
start
=
buffer
+
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
if
(
len
>
length
)
len
=
length
;
if
(
len
>
length
)
len
=
length
;
return
len
;
}
/*
* Find AX.25 route
*
* Only routes with a refernce rout of zero can be destroyed.
*/
static
ax25_route
*
ax25_
find
_route
(
ax25_address
*
addr
,
struct
net_device
*
dev
)
static
ax25_route
*
ax25_
get
_route
(
ax25_address
*
addr
,
struct
net_device
*
dev
)
{
ax25_route
*
ax25_spe_rt
=
NULL
;
ax25_route
*
ax25_def_rt
=
NULL
;
ax25_route
*
ax25_rt
;
read_lock
(
&
ax25_route_lock
);
/*
* Bind to the physical interface we heard them on, or the default
* route if none is found;
...
...
@@ -324,10 +369,16 @@ static ax25_route *ax25_find_route(ax25_address *addr, struct net_device *dev)
}
}
ax25_rt
=
ax25_def_rt
;
if
(
ax25_spe_rt
!=
NULL
)
return
ax25_spe_rt
;
ax25_rt
=
ax25_spe_rt
;
if
(
ax25_rt
!=
NULL
)
atomic_inc
(
&
ax25_rt
->
ref
);
return
ax25_def_rt
;
read_unlock
(
&
ax25_route_lock
);
return
ax25_rt
;
}
/*
...
...
@@ -355,24 +406,31 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
{
ax25_route
*
ax25_rt
;
ax25_address
*
call
;
int
err
;
if
((
ax25_rt
=
ax25_
find
_route
(
addr
,
NULL
))
==
NULL
)
if
((
ax25_rt
=
ax25_
get
_route
(
addr
,
NULL
))
==
NULL
)
return
-
EHOSTUNREACH
;
if
((
ax25
->
ax25_dev
=
ax25_dev_ax25dev
(
ax25_rt
->
dev
))
==
NULL
)
return
-
EHOSTUNREACH
;
if
((
ax25
->
ax25_dev
=
ax25_dev_ax25dev
(
ax25_rt
->
dev
))
==
NULL
)
{
err
=
-
EHOSTUNREACH
;
goto
put
;
}
if
((
call
=
ax25_findbyuid
(
current
->
euid
))
==
NULL
)
{
if
(
ax25_uid_policy
&&
!
capable
(
CAP_NET_BIND_SERVICE
))
return
-
EPERM
;
if
(
ax25_uid_policy
&&
!
capable
(
CAP_NET_BIND_SERVICE
))
{
err
=
-
EPERM
;
goto
put
;
}
call
=
(
ax25_address
*
)
ax25
->
ax25_dev
->
dev
->
dev_addr
;
}
ax25
->
source_addr
=
*
call
;
if
(
ax25_rt
->
digipeat
!=
NULL
)
{
if
((
ax25
->
digipeat
=
kmalloc
(
sizeof
(
ax25_digi
),
GFP_ATOMIC
))
==
NULL
)
return
-
ENOMEM
;
if
((
ax25
->
digipeat
=
kmalloc
(
sizeof
(
ax25_digi
),
GFP_ATOMIC
))
==
NULL
)
{
err
=
-
ENOMEM
;
goto
put
;
}
memcpy
(
ax25
->
digipeat
,
ax25_rt
->
digipeat
,
sizeof
(
ax25_digi
));
ax25_adjust_path
(
addr
,
ax25
->
digipeat
);
}
...
...
@@ -380,31 +438,32 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
if
(
ax25
->
sk
!=
NULL
)
ax25
->
sk
->
zapped
=
0
;
put:
ax25_put_route
(
ax25_rt
);
return
0
;
}
/*
* dl1bke 960117: build digipeater path
* dl1bke 960301: use the default route if it exists
*/
ax25_route
*
ax25_rt_find_route
(
ax25_address
*
addr
,
struct
net_device
*
dev
)
ax25_route
*
ax25_rt_find_route
(
ax25_route
*
route
,
ax25_address
*
addr
,
struct
net_device
*
dev
)
{
static
ax25_route
route
;
ax25_route
*
ax25_rt
;
if
((
ax25_rt
=
ax25_find_route
(
addr
,
dev
))
==
NULL
)
{
route
.
next
=
NULL
;
route
.
callsign
=
*
addr
;
route
.
dev
=
dev
;
route
.
digipeat
=
NULL
;
route
.
ip_mode
=
' '
;
return
&
route
;
}
if
((
ax25_rt
=
ax25_get_route
(
addr
,
dev
)))
return
ax25_rt
;
route
->
next
=
NULL
;
atomic_set
(
&
route
->
ref
,
1
);
route
->
callsign
=
*
addr
;
route
->
dev
=
dev
;
route
->
digipeat
=
NULL
;
route
->
ip_mode
=
' '
;
return
route
;
}
struct
sk_buff
*
ax25_rt_build_path
(
struct
sk_buff
*
skb
,
ax25_address
*
src
,
ax25_address
*
dest
,
ax25_digi
*
digi
)
struct
sk_buff
*
ax25_rt_build_path
(
struct
sk_buff
*
skb
,
ax25_address
*
src
,
ax25_address
*
dest
,
ax25_digi
*
digi
)
{
struct
sk_buff
*
skbn
;
unsigned
char
*
bp
;
...
...
@@ -440,6 +499,7 @@ void __exit ax25_rt_free(void)
{
ax25_route
*
s
,
*
ax25_rt
=
ax25_route_list
;
write_unlock
(
&
ax25_route_lock
);
while
(
ax25_rt
!=
NULL
)
{
s
=
ax25_rt
;
ax25_rt
=
ax25_rt
->
next
;
...
...
@@ -449,4 +509,5 @@ void __exit ax25_rt_free(void)
kfree
(
s
);
}
write_unlock
(
&
ax25_route_lock
);
}
net/ax25/ax25_std_in.c
View file @
a4041f6f
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
* Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams.
* AX.25 028b Jonathan(G4KLX) Extracted AX25 control block from
* the sock structure.
* AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names.
* Jonathan(G4KLX) Added IP mode registration.
* AX.25 030 Jonathan(G4KLX) Added AX.25 fragment reception.
* Upgraded state machine for SABME.
* Added arbitrary protocol id support.
* AX.25 031 Joerg(DL1BKE) Added DAMA support
* HaJo(DD8NE) Added Idle Disc Timer T5
* Joerg(DL1BKE) Renamed it to "IDLE" with a slightly
* different behaviour. Fixed defrag
* routine (I hope)
* AX.25 032 Darryl(G7LED) AX.25 segmentation fixed.
* AX.25 033 Jonathan(G4KLX) Remove auto-router.
* Modularisation changes.
* AX.25 035 Hans(PE1AYX) Fixed interface to IP layer.
* AX.25 036 Jonathan(G4KLX) Cloned from ax25_in.c.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Most of this code is based on the SDL diagrams published in the 7th ARRL
* Computer Networking Conference papers. The diagrams have mistakes in them,
* but are mostly correct. Before you modify the code could you read the SDL
* diagrams as the code is not obvious and probably very easy to break.
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
...
...
@@ -142,7 +119,8 @@ static int ax25_std_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
case
AX25_DM
:
case
AX25_UA
:
if
(
pf
)
ax25_disconnect
(
ax25
,
0
);
if
(
pf
)
ax25_disconnect
(
ax25
,
0
);
break
;
case
AX25_I
:
...
...
@@ -397,7 +375,8 @@ static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
}
ax25_frames_acked
(
ax25
,
nr
);
if
(
ax25
->
condition
&
AX25_COND_OWN_RX_BUSY
)
{
if
(
pf
)
ax25_std_enquiry_response
(
ax25
);
if
(
pf
)
ax25_std_enquiry_response
(
ax25
);
break
;
}
if
(
ns
==
ax25
->
vr
)
{
...
...
net/ax25/ax25_std_subr.c
View file @
a4041f6f
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* AX.25 036 Jonathan(G4KLX) Split from ax25_out.c.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
...
...
net/ax25/ax25_std_timer.c
View file @
a4041f6f
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams.
* AX.25 028b Jonathan(G4KLX) Extracted AX25 control block from the
* sock structure.
* AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names.
* AX.25 031 Joerg(DL1BKE) Added DAMA support
* AX.25 032 Joerg(DL1BKE) Fixed DAMA timeout bug
* AX.25 033 Jonathan(G4KLX) Modularisation functions.
* AX.25 035 Frederic(F1OAT) Support for pseudo-digipeating.
* AX.25 036 Jonathan(G4KLX) Split from ax25_timer.c.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
...
...
@@ -47,7 +34,6 @@
void
ax25_std_heartbeat_expiry
(
ax25_cb
*
ax25
)
{
switch
(
ax25
->
state
)
{
case
AX25_STATE_0
:
/* Magic here: If we listen() and a new link dies before it
is accepted() it isn't 'dead' so doesn't get removed. */
...
...
net/ax25/ax25_subr.c
View file @
a4041f6f
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names. Removed
* old BSD code.
* AX.25 030 Jonathan(G4KLX) Added support for extended AX.25.
* Added fragmentation support.
* Darryl(G7LED) Added function ax25_requeue_frames() to split
* it up from ax25_frames_acked().
* AX.25 031 Joerg(DL1BKE) DAMA needs KISS Fullduplex ON/OFF.
* Thus we have ax25_kiss_cmd() now... ;-)
* Dave Brown(N2RJT)
* Killed a silly bug in the DAMA code.
* Joerg(DL1BKE) Found the real bug in ax25.h, sri.
* AX.25 032 Joerg(DL1BKE) Added ax25_queue_length to count the number of
* enqueued buffers of a socket..
* AX.25 035 Frederic(F1OAT) Support for pseudo-digipeating.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
...
...
net/ax25/ax25_timer.c
View file @
a4041f6f
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams.
* AX.25 028b Jonathan(G4KLX) Extracted AX25 control block from the
* sock structure.
* AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names.
* AX.25 031 Joerg(DL1BKE) Added DAMA support
* AX.25 032 Joerg(DL1BKE) Fixed DAMA timeout bug
* AX.25 033 Jonathan(G4KLX) Modularisation functions.
* AX.25 035 Frederic(F1OAT) Support for pseudo-digipeating.
* AX.25 036 Jonathan(G4KLX) Split Standard and DAMA code into separate files.
* Joerg(DL1BKE) Fixed DAMA Slave. We are *required* to start with
* standard AX.25 mode.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Tomi(OH2BNS) Fixed heartbeat expiry (check ax25_dev).
* Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Tomi Manninen OH2BNS (oh2bns@sral.fi)
* Copyright (C) Darryl Miles G7LED (dlm@g7led.demon.co.uk)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
* Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org)
*/
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
...
...
@@ -152,12 +139,15 @@ unsigned long ax25_display_timer(struct timer_list *timer)
static
void
ax25_heartbeat_expiry
(
unsigned
long
param
)
{
ax25_cb
*
ax25
=
(
ax25_cb
*
)
param
;
int
proto
=
AX25_PROTO_STD_SIMPLEX
;
ax25_cb
*
ax25
=
(
ax25_cb
*
)
param
;
struct
sock
*
sk
=
ax25
->
sk
;
if
(
ax25
->
ax25_dev
)
proto
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
];
bh_lock_sock
(
sk
);
switch
(
proto
)
{
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
...
...
@@ -173,12 +163,15 @@ static void ax25_heartbeat_expiry(unsigned long param)
break
;
#endif
}
bh_unlock_sock
(
sk
);
}
static
void
ax25_t1timer_expiry
(
unsigned
long
param
)
{
ax25_cb
*
ax25
=
(
ax25_cb
*
)
param
;
struct
sock
*
sk
=
ax25
->
sk
;
bh_lock_sock
(
sk
);
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
...
...
@@ -192,12 +185,15 @@ static void ax25_t1timer_expiry(unsigned long param)
break
;
#endif
}
bh_unlock_sock
(
sk
);
}
static
void
ax25_t2timer_expiry
(
unsigned
long
param
)
{
ax25_cb
*
ax25
=
(
ax25_cb
*
)
param
;
struct
sock
*
sk
=
ax25
->
sk
;
bh_lock_sock
(
sk
);
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
...
...
@@ -211,12 +207,15 @@ static void ax25_t2timer_expiry(unsigned long param)
break
;
#endif
}
bh_unlock_sock
(
sk
);
}
static
void
ax25_t3timer_expiry
(
unsigned
long
param
)
{
ax25_cb
*
ax25
=
(
ax25_cb
*
)
param
;
struct
sock
*
sk
=
ax25
->
sk
;
bh_lock_sock
(
sk
);
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
...
...
@@ -232,12 +231,15 @@ static void ax25_t3timer_expiry(unsigned long param)
break
;
#endif
}
bh_unlock_sock
(
sk
);
}
static
void
ax25_idletimer_expiry
(
unsigned
long
param
)
{
ax25_cb
*
ax25
=
(
ax25_cb
*
)
param
;
struct
sock
*
sk
=
ax25
->
sk
;
bh_lock_sock
(
sk
);
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
...
...
@@ -253,4 +255,5 @@ static void ax25_idletimer_expiry(unsigned long param)
break
;
#endif
}
bh_unlock_sock
(
sk
);
}
net/ax25/ax25_uid.c
View file @
a4041f6f
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* AX.25 036 Jonathan(G4KLX) Split from af_ax25.c.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
...
...
@@ -23,6 +16,7 @@
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/spinlock.h>
#include <net/ax25.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
...
...
@@ -47,17 +41,23 @@
*/
static
ax25_uid_assoc
*
ax25_uid_list
;
static
rwlock_t
ax25_uid_lock
=
RW_LOCK_UNLOCKED
;
int
ax25_uid_policy
=
0
;
ax25_address
*
ax25_findbyuid
(
uid_t
uid
)
{
ax25_uid_assoc
*
ax25_uid
;
ax25_address
*
res
=
NULL
;
read_lock
(
&
ax25_uid_lock
);
for
(
ax25_uid
=
ax25_uid_list
;
ax25_uid
!=
NULL
;
ax25_uid
=
ax25_uid
->
next
)
{
if
(
ax25_uid
->
uid
==
uid
)
return
&
ax25_uid
->
call
;
if
(
ax25_uid
->
uid
==
uid
)
{
res
=
&
ax25_uid
->
call
;
break
;
}
}
read_unlock
(
&
ax25_uid_lock
);
return
NULL
;
}
...
...
@@ -65,15 +65,21 @@ ax25_address *ax25_findbyuid(uid_t uid)
int
ax25_uid_ioctl
(
int
cmd
,
struct
sockaddr_ax25
*
sax
)
{
ax25_uid_assoc
*
s
,
*
ax25_uid
;
unsigned
long
flag
s
;
unsigned
long
re
s
;
switch
(
cmd
)
{
case
SIOCAX25GETUID
:
res
=
-
ENOENT
;
read_lock
(
&
ax25_uid_lock
);
for
(
ax25_uid
=
ax25_uid_list
;
ax25_uid
!=
NULL
;
ax25_uid
=
ax25_uid
->
next
)
{
if
(
ax25cmp
(
&
sax
->
sax25_call
,
&
ax25_uid
->
call
)
==
0
)
return
ax25_uid
->
uid
;
if
(
ax25cmp
(
&
sax
->
sax25_call
,
&
ax25_uid
->
call
)
==
0
)
{
res
=
ax25_uid
->
uid
;
break
;
}
return
-
ENOENT
;
}
read_unlock
(
&
ax25_uid_lock
);
return
res
;
case
SIOCAX25ADDUID
:
if
(
!
capable
(
CAP_NET_ADMIN
))
...
...
@@ -84,40 +90,48 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
return
-
EINVAL
;
if
((
ax25_uid
=
kmalloc
(
sizeof
(
*
ax25_uid
),
GFP_KERNEL
))
==
NULL
)
return
-
ENOMEM
;
ax25_uid
->
uid
=
sax
->
sax25_uid
;
ax25_uid
->
call
=
sax
->
sax25_call
;
save_flags
(
flags
);
cli
();
write_lock
(
&
ax25_uid_lock
);
ax25_uid
->
next
=
ax25_uid_list
;
ax25_uid_list
=
ax25_uid
;
restore_flags
(
flags
);
write_unlock
(
&
ax25_uid_lock
);
return
0
;
case
SIOCAX25DELUID
:
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
write_lock
(
&
ax25_uid_lock
);
for
(
ax25_uid
=
ax25_uid_list
;
ax25_uid
!=
NULL
;
ax25_uid
=
ax25_uid
->
next
)
{
if
(
ax25cmp
(
&
sax
->
sax25_call
,
&
ax25_uid
->
call
)
==
0
)
if
(
ax25cmp
(
&
sax
->
sax25_call
,
&
ax25_uid
->
call
)
==
0
)
{
break
;
}
if
(
ax25_uid
==
NULL
)
}
if
(
ax25_uid
==
NULL
)
{
write_unlock
(
&
ax25_uid_lock
);
return
-
ENOENT
;
save_flags
(
flags
);
cli
();
}
if
((
s
=
ax25_uid_list
)
==
ax25_uid
)
{
ax25_uid_list
=
s
->
next
;
restore_flags
(
flags
);
write_unlock
(
&
ax25_uid_lock
);
kfree
(
ax25_uid
);
return
0
;
}
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
if
(
s
->
next
==
ax25_uid
)
{
s
->
next
=
ax25_uid
->
next
;
restore_flags
(
flags
);
write_unlock
(
&
ax25_uid_lock
);
kfree
(
ax25_uid
);
return
0
;
}
s
=
s
->
next
;
}
restore_flags
(
flags
);
write_unlock
(
&
ax25_uid_lock
);
return
-
ENOENT
;
default:
...
...
@@ -134,8 +148,7 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length)
off_t
pos
=
0
;
off_t
begin
=
0
;
cli
();
read_lock
(
&
ax25_uid_lock
);
len
+=
sprintf
(
buffer
,
"Policy: %d
\n
"
,
ax25_uid_policy
);
for
(
pt
=
ax25_uid_list
;
pt
!=
NULL
;
pt
=
pt
->
next
)
{
...
...
@@ -151,13 +164,13 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length)
if
(
pos
>
offset
+
length
)
break
;
}
sti
();
read_unlock
(
&
ax25_uid_lock
);
*
start
=
buffer
+
(
offset
-
begin
);
len
-=
offset
-
begin
;
if
(
len
>
length
)
len
=
length
;
if
(
len
>
length
)
len
=
length
;
return
len
;
}
...
...
@@ -167,12 +180,16 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length)
*/
void
__exit
ax25_uid_free
(
void
)
{
ax25_uid_assoc
*
s
,
*
ax25_uid
=
ax25_uid_list
;
ax25_uid_assoc
*
s
,
*
ax25_uid
;
write_lock
(
&
ax25_uid_lock
);
ax25_uid
=
ax25_uid_list
;
while
(
ax25_uid
!=
NULL
)
{
s
=
ax25_uid
;
ax25_uid
=
ax25_uid
->
next
;
kfree
(
s
);
}
ax25_uid_list
=
NULL
;
write_unlock
(
&
ax25_uid_lock
);
}
net/ax25/sysctl_net_ax25.c
View file @
a4041f6f
/* -*- linux-c -*-
* sysctl_net_ax25.c: sysctl interface to net AX.25 subsystem.
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Begun April 1, 1996, Mike Shaver.
* Added /proc/sys/net/ax25 directory entry (empty =) ). [MS]
* Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com)
*/
#include <linux/config.h>
#include <linux/mm.h>
#include <linux/sysctl.h>
#include <linux/spinlock.h>
#include <net/ax25.h>
static
int
min_ipdefmode
[]
=
{
0
},
max_ipdefmode
[]
=
{
1
};
...
...
@@ -105,6 +107,7 @@ void ax25_register_sysctl(void)
ax25_dev
*
ax25_dev
;
int
n
,
k
;
spin_lock_bh
(
&
ax25_dev_lock
);
for
(
ax25_table_size
=
sizeof
(
ctl_table
),
ax25_dev
=
ax25_dev_list
;
ax25_dev
!=
NULL
;
ax25_dev
=
ax25_dev
->
next
)
ax25_table_size
+=
sizeof
(
ctl_table
);
...
...
@@ -119,6 +122,7 @@ void ax25_register_sysctl(void)
while
(
n
--
)
kfree
(
ax25_table
[
n
].
child
);
kfree
(
ax25_table
);
spin_unlock_bh
(
&
ax25_dev_lock
);
return
;
}
memcpy
(
child
,
ax25_param_table
,
sizeof
(
ax25_param_table
));
...
...
@@ -144,6 +148,7 @@ void ax25_register_sysctl(void)
n
++
;
}
spin_unlock_bh
(
&
ax25_dev_lock
);
ax25_dir_table
[
0
].
child
=
ax25_table
;
...
...
net/llc/llc_actn.c
View file @
a4041f6f
...
...
@@ -24,16 +24,10 @@
#include <net/llc_pdu.h>
#include <net/llc_mac.h>
static
void
llc_station_ack_tmr_callback
(
unsigned
long
timeout_data
);
int
llc_station_ac_start_ack_timer
(
struct
llc_station
*
station
,
struct
sk_buff
*
skb
)
{
del_timer
(
&
station
->
ack_timer
);
station
->
ack_timer
.
expires
=
jiffies
+
LLC_ACK_TIME
*
HZ
;
station
->
ack_timer
.
data
=
(
unsigned
long
)
station
;
station
->
ack_timer
.
function
=
llc_station_ack_tmr_callback
;
add_timer
(
&
station
->
ack_timer
);
mod_timer
(
&
station
->
ack_timer
,
jiffies
+
LLC_ACK_TIME
*
HZ
);
return
0
;
}
...
...
@@ -130,7 +124,7 @@ int llc_station_ac_report_status(struct llc_station *station,
return
0
;
}
static
void
llc_station_ack_tmr_callback
(
unsigned
long
timeout_data
)
void
llc_station_ack_tmr_cb
(
unsigned
long
timeout_data
)
{
struct
llc_station
*
station
=
(
struct
llc_station
*
)
timeout_data
;
struct
sk_buff
*
skb
=
alloc_skb
(
0
,
GFP_ATOMIC
);
...
...
net/llc/llc_c_ac.c
View file @
a4041f6f
...
...
@@ -28,10 +28,6 @@
#include <net/llc_pdu.h>
#include <net/llc_mac.h>
static
void
llc_conn_pf_cycle_tmr_cb
(
unsigned
long
timeout_data
);
static
void
llc_conn_ack_tmr_cb
(
unsigned
long
timeout_data
);
static
void
llc_conn_rej_tmr_cb
(
unsigned
long
timeout_data
);
static
void
llc_conn_busy_tmr_cb
(
unsigned
long
timeout_data
);
static
int
llc_conn_ac_inc_vs_by_1
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
);
static
void
llc_process_tmr_ev
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
);
static
int
llc_conn_ac_data_confirm
(
struct
sock
*
sk
,
struct
sk_buff
*
ev
);
...
...
@@ -664,11 +660,8 @@ int llc_conn_ac_set_remote_busy(struct sock *sk, struct sk_buff *skb)
if
(
!
llc
->
remote_busy_flag
)
{
llc
->
remote_busy_flag
=
1
;
llc
->
busy_state_timer
.
timer
.
expires
=
jiffies
+
llc
->
busy_state_timer
.
expire
*
HZ
;
llc
->
busy_state_timer
.
timer
.
data
=
(
unsigned
long
)
sk
;
llc
->
busy_state_timer
.
timer
.
function
=
llc_conn_busy_tmr_cb
;
add_timer
(
&
llc
->
busy_state_timer
.
timer
);
mod_timer
(
&
llc
->
busy_state_timer
.
timer
,
jiffies
+
llc
->
busy_state_timer
.
expire
*
HZ
);
}
return
0
;
}
...
...
@@ -905,12 +898,8 @@ int llc_conn_ac_start_p_timer(struct sock *sk, struct sk_buff *skb)
struct
llc_opt
*
llc
=
llc_sk
(
sk
);
llc
->
p_flag
=
1
;
del_timer
(
&
llc
->
pf_cycle_timer
.
timer
);
llc
->
pf_cycle_timer
.
timer
.
expires
=
jiffies
+
llc
->
pf_cycle_timer
.
expire
*
HZ
;
llc
->
pf_cycle_timer
.
timer
.
data
=
(
unsigned
long
)
sk
;
llc
->
pf_cycle_timer
.
timer
.
function
=
llc_conn_pf_cycle_tmr_cb
;
add_timer
(
&
llc
->
pf_cycle_timer
.
timer
);
mod_timer
(
&
llc
->
pf_cycle_timer
.
timer
,
jiffies
+
llc
->
pf_cycle_timer
.
expire
*
HZ
);
return
0
;
}
...
...
@@ -1181,11 +1170,7 @@ int llc_conn_ac_start_ack_timer(struct sock *sk, struct sk_buff *skb)
{
struct
llc_opt
*
llc
=
llc_sk
(
sk
);
del_timer
(
&
llc
->
ack_timer
.
timer
);
llc
->
ack_timer
.
timer
.
expires
=
jiffies
+
llc
->
ack_timer
.
expire
*
HZ
;
llc
->
ack_timer
.
timer
.
data
=
(
unsigned
long
)
sk
;
llc
->
ack_timer
.
timer
.
function
=
llc_conn_ack_tmr_cb
;
add_timer
(
&
llc
->
ack_timer
.
timer
);
mod_timer
(
&
llc
->
ack_timer
.
timer
,
jiffies
+
llc
->
ack_timer
.
expire
*
HZ
);
return
0
;
}
...
...
@@ -1193,12 +1178,8 @@ int llc_conn_ac_start_rej_timer(struct sock *sk, struct sk_buff *skb)
{
struct
llc_opt
*
llc
=
llc_sk
(
sk
);
del_timer
(
&
llc
->
rej_sent_timer
.
timer
);
llc
->
rej_sent_timer
.
timer
.
expires
=
jiffies
+
llc
->
rej_sent_timer
.
expire
*
HZ
;
llc
->
rej_sent_timer
.
timer
.
data
=
(
unsigned
long
)
sk
;
llc
->
rej_sent_timer
.
timer
.
function
=
llc_conn_rej_tmr_cb
;
add_timer
(
&
llc
->
rej_sent_timer
.
timer
);
mod_timer
(
&
llc
->
rej_sent_timer
.
timer
,
jiffies
+
llc
->
rej_sent_timer
.
expire
*
HZ
);
return
0
;
}
...
...
@@ -1207,13 +1188,9 @@ int llc_conn_ac_start_ack_tmr_if_not_running(struct sock *sk,
{
struct
llc_opt
*
llc
=
llc_sk
(
sk
);
if
(
!
timer_pending
(
&
llc
->
ack_timer
.
timer
))
{
llc
->
ack_timer
.
timer
.
expires
=
jiffies
+
llc
->
ack_timer
.
expire
*
HZ
;
llc
->
ack_timer
.
timer
.
data
=
(
unsigned
long
)
sk
;
llc
->
ack_timer
.
timer
.
function
=
llc_conn_ack_tmr_cb
;
add_timer
(
&
llc
->
ack_timer
.
timer
);
}
if
(
!
timer_pending
(
&
llc
->
ack_timer
.
timer
))
mod_timer
(
&
llc
->
ack_timer
.
timer
,
jiffies
+
llc
->
ack_timer
.
expire
*
HZ
);
return
0
;
}
...
...
@@ -1260,13 +1237,9 @@ int llc_conn_ac_upd_nr_received(struct sock *sk, struct sk_buff *skb)
llc
->
failed_data_req
=
0
;
llc_conn_ac_data_confirm
(
sk
,
skb
);
}
if
(
unacked
)
{
llc
->
ack_timer
.
timer
.
expires
=
jiffies
+
llc
->
ack_timer
.
expire
*
HZ
;
llc
->
ack_timer
.
timer
.
data
=
(
unsigned
long
)
sk
;
llc
->
ack_timer
.
timer
.
function
=
llc_conn_ack_tmr_cb
;
add_timer
(
&
llc
->
ack_timer
.
timer
);
}
if
(
unacked
)
mod_timer
(
&
llc
->
ack_timer
.
timer
,
jiffies
+
llc
->
ack_timer
.
expire
*
HZ
);
}
else
if
(
llc
->
failed_data_req
)
{
llc_pdu_decode_pf_bit
(
skb
,
&
fbit
);
if
(
fbit
==
1
)
{
...
...
@@ -1413,7 +1386,7 @@ void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data)
bh_unlock_sock
(
sk
);
}
static
void
llc_conn_busy_tmr_cb
(
unsigned
long
timeout_data
)
void
llc_conn_busy_tmr_cb
(
unsigned
long
timeout_data
)
{
struct
sock
*
sk
=
(
struct
sock
*
)
timeout_data
;
struct
sk_buff
*
skb
=
alloc_skb
(
0
,
GFP_ATOMIC
);
...
...
@@ -1445,7 +1418,7 @@ void llc_conn_ack_tmr_cb(unsigned long timeout_data)
bh_unlock_sock
(
sk
);
}
static
void
llc_conn_rej_tmr_cb
(
unsigned
long
timeout_data
)
void
llc_conn_rej_tmr_cb
(
unsigned
long
timeout_data
)
{
struct
sock
*
sk
=
(
struct
sock
*
)
timeout_data
;
struct
sk_buff
*
skb
=
alloc_skb
(
0
,
GFP_ATOMIC
);
...
...
net/llc/llc_c_ev.c
View file @
a4041f6f
...
...
@@ -194,7 +194,8 @@ int llc_conn_ev_rx_i_cmd_pbit_set_0(struct sock *sk, struct sk_buff *skb)
{
struct
llc_pdu_sn
*
pdu
=
llc_pdu_sn_hdr
(
skb
);
return
!
LLC_PDU_IS_CMD
(
pdu
)
&&
!
LLC_PDU_TYPE_IS_I
(
pdu
)
&&
return
llc_conn_space
(
sk
,
skb
)
&&
!
LLC_PDU_IS_CMD
(
pdu
)
&&
!
LLC_PDU_TYPE_IS_I
(
pdu
)
&&
!
LLC_I_PF_IS_0
(
pdu
)
&&
LLC_I_GET_NS
(
pdu
)
==
llc_sk
(
sk
)
->
vR
?
0
:
1
;
}
...
...
@@ -203,7 +204,8 @@ int llc_conn_ev_rx_i_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb)
{
struct
llc_pdu_sn
*
pdu
=
llc_pdu_sn_hdr
(
skb
);
return
!
LLC_PDU_IS_CMD
(
pdu
)
&&
!
LLC_PDU_TYPE_IS_I
(
pdu
)
&&
return
llc_conn_space
(
sk
,
skb
)
&&
!
LLC_PDU_IS_CMD
(
pdu
)
&&
!
LLC_PDU_TYPE_IS_I
(
pdu
)
&&
!
LLC_I_PF_IS_1
(
pdu
)
&&
LLC_I_GET_NS
(
pdu
)
==
llc_sk
(
sk
)
->
vR
?
0
:
1
;
}
...
...
@@ -250,7 +252,8 @@ int llc_conn_ev_rx_i_rsp_fbit_set_0(struct sock *sk, struct sk_buff *skb)
{
struct
llc_pdu_sn
*
pdu
=
llc_pdu_sn_hdr
(
skb
);
return
!
LLC_PDU_IS_RSP
(
pdu
)
&&
!
LLC_PDU_TYPE_IS_I
(
pdu
)
&&
return
llc_conn_space
(
sk
,
skb
)
&&
!
LLC_PDU_IS_RSP
(
pdu
)
&&
!
LLC_PDU_TYPE_IS_I
(
pdu
)
&&
!
LLC_I_PF_IS_0
(
pdu
)
&&
LLC_I_GET_NS
(
pdu
)
==
llc_sk
(
sk
)
->
vR
?
0
:
1
;
}
...
...
@@ -268,7 +271,8 @@ int llc_conn_ev_rx_i_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb)
{
struct
llc_pdu_sn
*
pdu
=
llc_pdu_sn_hdr
(
skb
);
return
!
LLC_PDU_IS_RSP
(
pdu
)
&&
!
LLC_PDU_TYPE_IS_I
(
pdu
)
&&
return
llc_conn_space
(
sk
,
skb
)
&&
!
LLC_PDU_IS_RSP
(
pdu
)
&&
!
LLC_PDU_TYPE_IS_I
(
pdu
)
&&
LLC_I_GET_NS
(
pdu
)
==
llc_sk
(
sk
)
->
vR
?
0
:
1
;
}
...
...
@@ -423,7 +427,8 @@ int llc_conn_ev_rx_rr_rsp_fbit_set_0(struct sock *sk, struct sk_buff *skb)
{
struct
llc_pdu_sn
*
pdu
=
llc_pdu_sn_hdr
(
skb
);
return
!
LLC_PDU_IS_RSP
(
pdu
)
&&
!
LLC_PDU_TYPE_IS_S
(
pdu
)
&&
return
llc_conn_space
(
sk
,
skb
)
&&
!
LLC_PDU_IS_RSP
(
pdu
)
&&
!
LLC_PDU_TYPE_IS_S
(
pdu
)
&&
!
LLC_S_PF_IS_0
(
pdu
)
&&
LLC_S_PDU_RSP
(
pdu
)
==
LLC_2_PDU_RSP_RR
?
0
:
1
;
}
...
...
@@ -432,7 +437,8 @@ int llc_conn_ev_rx_rr_rsp_fbit_set_1(struct sock *sk, struct sk_buff *skb)
{
struct
llc_pdu_sn
*
pdu
=
llc_pdu_sn_hdr
(
skb
);
return
!
LLC_PDU_IS_RSP
(
pdu
)
&&
!
LLC_PDU_TYPE_IS_S
(
pdu
)
&&
return
llc_conn_space
(
sk
,
skb
)
&&
!
LLC_PDU_IS_RSP
(
pdu
)
&&
!
LLC_PDU_TYPE_IS_S
(
pdu
)
&&
!
LLC_S_PF_IS_1
(
pdu
)
&&
LLC_S_PDU_RSP
(
pdu
)
==
LLC_2_PDU_RSP_RR
?
0
:
1
;
}
...
...
net/llc/llc_main.c
View file @
a4041f6f
...
...
@@ -184,19 +184,32 @@ int llc_sk_init(struct sock* sk)
goto
out
;
memset
(
llc
,
0
,
sizeof
(
*
llc
));
rc
=
0
;
llc
->
sk
=
sk
;
llc
->
state
=
LLC_CONN_STATE_ADM
;
llc
->
inc_cntr
=
llc
->
dec_cntr
=
2
;
llc
->
dec_step
=
llc
->
connect_step
=
1
;
llc
->
ack_timer
.
expire
=
LLC_ACK_TIME
;
llc
->
ack_timer
.
timer
.
data
=
(
unsigned
long
)
sk
;
llc
->
ack_timer
.
timer
.
function
=
llc_conn_ack_tmr_cb
;
llc
->
pf_cycle_timer
.
expire
=
LLC_P_TIME
;
llc
->
pf_cycle_timer
.
timer
.
data
=
(
unsigned
long
)
sk
;
llc
->
pf_cycle_timer
.
timer
.
function
=
llc_conn_pf_cycle_tmr_cb
;
llc
->
rej_sent_timer
.
expire
=
LLC_REJ_TIME
;
llc
->
rej_sent_timer
.
timer
.
data
=
(
unsigned
long
)
sk
;
llc
->
rej_sent_timer
.
timer
.
function
=
llc_conn_rej_tmr_cb
;
llc
->
busy_state_timer
.
expire
=
LLC_BUSY_TIME
;
llc
->
busy_state_timer
.
timer
.
data
=
(
unsigned
long
)
sk
;
llc
->
busy_state_timer
.
timer
.
function
=
llc_conn_busy_tmr_cb
;
llc
->
n2
=
2
;
/* max retransmit */
llc
->
k
=
2
;
/* tx win size, will adjust dynam */
llc
->
rw
=
128
;
/* rx win size (opt and equal to
* tx_win of remote LLC)
*/
* tx_win of remote LLC) */
skb_queue_head_init
(
&
llc
->
pdu_unack_q
);
sk
->
backlog_rcv
=
llc_backlog_rcv
;
llc_sk
(
sk
)
=
llc
;
...
...
@@ -534,6 +547,21 @@ struct sk_buff *llc_alloc_frame(void)
return
skb
;
}
static
char
*
llc_conn_state_names
[]
=
{
[
LLC_CONN_STATE_ADM
]
=
"adm"
,
[
LLC_CONN_STATE_SETUP
]
=
"setup"
,
[
LLC_CONN_STATE_NORMAL
]
=
"normal"
,
[
LLC_CONN_STATE_BUSY
]
=
"busy"
,
[
LLC_CONN_STATE_REJ
]
=
"rej"
,
[
LLC_CONN_STATE_AWAIT
]
=
"await"
,
[
LLC_CONN_STATE_AWAIT_BUSY
]
=
"await_busy"
,
[
LLC_CONN_STATE_AWAIT_REJ
]
=
"await_rej"
,
[
LLC_CONN_STATE_D_CONN
]
=
"d_conn"
,
[
LLC_CONN_STATE_RESET
]
=
"reset"
,
[
LLC_CONN_STATE_ERROR
]
=
"error"
,
[
LLC_CONN_STATE_TEMP
]
=
"temp"
,
};
static
int
llc_proc_get_info
(
char
*
bf
,
char
**
start
,
off_t
offset
,
int
length
)
{
struct
llc_opt
*
llc
;
...
...
@@ -546,19 +574,34 @@ static int llc_proc_get_info(char *bf, char **start, off_t offset, int length)
struct
llc_sap
*
sap
=
list_entry
(
sap_entry
,
struct
llc_sap
,
node
);
len
+=
sprintf
(
bf
+
len
,
"lsap=%
d
\n
"
,
sap
->
laddr
.
lsap
);
len
+=
sprintf
(
bf
+
len
,
"lsap=%
02X
\n
"
,
sap
->
laddr
.
lsap
);
spin_lock_bh
(
&
sap
->
sk_list
.
lock
);
if
(
list_empty
(
&
sap
->
sk_list
.
list
))
{
len
+=
sprintf
(
bf
+
len
,
"no connections
\n
"
);
goto
unlock
;
}
len
+=
sprintf
(
bf
+
len
,
"connection list:
\n
state retr txwin rxwin
\n
"
);
len
+=
sprintf
(
bf
+
len
,
"connection list:
\n
"
"dsap state retr txw rxw "
"pf ff sf df rs cs "
"tack tpfc trs tbs blog busr
\n
"
);
list_for_each
(
llc_entry
,
&
sap
->
sk_list
.
list
)
{
llc
=
list_entry
(
llc_entry
,
struct
llc_opt
,
node
);
len
+=
sprintf
(
bf
+
len
,
" %-5d%-5d%-6d%-5d
\n
"
,
llc
->
state
,
llc
->
retry_count
,
llc
->
k
,
llc
->
rw
);
len
+=
sprintf
(
bf
+
len
,
" %02X %-10s %3d %3d %3d "
"%2d %2d %2d "
"%2d %2d %2d "
"%4d %4d %3d %3d %4d %4d
\n
"
,
llc
->
daddr
.
lsap
,
llc_conn_state_names
[
llc
->
state
],
llc
->
retry_count
,
llc
->
k
,
llc
->
rw
,
llc
->
p_flag
,
llc
->
f_flag
,
llc
->
s_flag
,
llc
->
data_flag
,
llc
->
remote_busy_flag
,
llc
->
cause_flag
,
timer_pending
(
&
llc
->
ack_timer
.
timer
),
timer_pending
(
&
llc
->
pf_cycle_timer
.
timer
),
timer_pending
(
&
llc
->
rej_sent_timer
.
timer
),
timer_pending
(
&
llc
->
busy_state_timer
.
timer
),
!!
llc
->
sk
->
backlog
.
tail
,
llc
->
sk
->
lock
.
users
);
}
unlock:
spin_unlock_bh
(
&
sap
->
sk_list
.
lock
);
...
...
@@ -608,6 +651,9 @@ static int __init llc_init(void)
skb_queue_head_init
(
&
llc_main_station
.
mac_pdu_q
);
skb_queue_head_init
(
&
llc_main_station
.
ev_q
.
list
);
spin_lock_init
(
&
llc_main_station
.
ev_q
.
lock
);
llc_main_station
.
ack_timer
.
data
=
(
unsigned
long
)
&
llc_main_station
;
llc_main_station
.
ack_timer
.
function
=
llc_station_ack_tmr_cb
;
skb
=
alloc_skb
(
0
,
GFP_ATOMIC
);
if
(
!
skb
)
goto
err
;
...
...
net/llc/llc_sock.c
View file @
a4041f6f
...
...
@@ -360,11 +360,11 @@ static int llc_ui_release(struct socket *sock)
llc
->
laddr
.
lsap
,
llc
->
daddr
.
lsap
);
if
(
!
llc_send_disc
(
sk
))
llc_ui_wait_for_disc
(
sk
,
sk
->
rcvtimeo
);
release_sock
(
sk
);
if
(
!
sk
->
zapped
)
{
llc_sap_unassign_sock
(
llc
->
sap
,
sk
);
llc_ui_remove_socket
(
sk
);
}
release_sock
(
sk
);
if
(
llc
->
sap
&&
list_empty
(
&
llc
->
sap
->
sk_list
.
list
))
llc_sap_close
(
llc
->
sap
);
sock_put
(
sk
);
...
...
@@ -484,10 +484,10 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
llc
->
daddr
.
lsap
=
addr
->
sllc_dsap
;
memcpy
(
llc
->
daddr
.
mac
,
addr
->
sllc_dmac
,
IFHWADDRLEN
);
memcpy
(
&
llc
->
addr
,
addr
,
sizeof
(
llc
->
addr
));
rc
=
sk
->
zapped
=
0
;
llc_ui_insert_socket
(
sk
);
/* assign new connection to it's SAP */
llc_sap_assign_sock
(
sap
,
sk
);
rc
=
sk
->
zapped
=
0
;
out:
return
rc
;
}
...
...
@@ -952,7 +952,9 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len,
if
(
size
>
dev
->
mtu
)
size
=
dev
->
mtu
;
copied
=
size
-
hdrlen
;
release_sock
(
sk
);
skb
=
sock_alloc_send_skb
(
sk
,
size
,
noblock
,
&
rc
);
lock_sock
(
sk
);
if
(
!
skb
)
goto
release
;
skb
->
sk
=
sk
;
...
...
net/netrom/af_netrom.c
View file @
a4041f6f
/*
* NET/ROM release 007
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* NET/ROM 001 Jonathan(G4KLX) Cloned from the AX25 code.
* NET/ROM 002 Darryl(G7LED) Fixes and address enhancement.
* Jonathan(G4KLX) Complete bind re-think.
* Alan(GW4PTS) Trivial tweaks into new format.
* NET/ROM 003 Jonathan(G4KLX) Added G8BPQ extensions.
* Added NET/ROM routing ioctl.
* Darryl(G7LED) Fix autobinding (on connect).
* Fixed nr_release(), set TCP_CLOSE, wakeup app
* context, THEN make the sock dead.
* Circuit ID check before allocating it on
* a connection.
* Alan(GW4PTS) sendmsg/recvmsg only. Fixed connect clear bug
* inherited from AX.25
* NET/ROM 004 Jonathan(G4KLX) Converted to module.
* NET/ROM 005 Jonathan(G4KLX) Linux 2.1
* Alan(GW4PTS) Started POSIXisms
* NET/ROM 006 Alan(GW4PTS) Brought in line with the ANK changes
* Jonathan(G4KLX) Removed hdrincl.
* NET/ROM 007 Jonathan(G4KLX) New timer architecture.
* Implemented Idle timer.
* Arnaldo C. Melo s/suser/capable/, micro cleanups
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk)
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
...
...
@@ -82,7 +57,8 @@ int sysctl_netrom_link_fails_count = NR_DEFAULT_FAILS;
static
unsigned
short
circuit
=
0x101
;
static
struct
sock
*
volatile
nr_list
;
static
struct
sock
*
nr_list
;
static
spinlock_t
nr_list_lock
;
static
struct
proto_ops
nr_proto_ops
;
...
...
@@ -123,27 +99,26 @@ decmod: MOD_DEC_USE_COUNT;
static
void
nr_remove_socket
(
struct
sock
*
sk
)
{
struct
sock
*
s
;
unsigned
long
flags
;
s
ave_flags
(
flags
);
cli
(
);
s
pin_lock_bh
(
&
nr_list_lock
);
if
((
s
=
nr_list
)
==
sk
)
{
nr_list
=
s
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_list_lock
);
return
;
}
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
if
(
s
->
next
==
sk
)
{
s
->
next
=
sk
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_list_lock
);
return
;
}
s
=
s
->
next
;
}
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_list_lock
);
}
/*
...
...
@@ -153,10 +128,12 @@ static void nr_kill_by_device(struct net_device *dev)
{
struct
sock
*
s
;
spin_lock_bh
(
&
nr_list_lock
);
for
(
s
=
nr_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
if
(
nr_sk
(
s
)
->
device
==
dev
)
nr_disconnect
(
s
,
ENETUNREACH
);
}
spin_unlock_bh
(
&
nr_list_lock
);
}
/*
...
...
@@ -180,14 +157,10 @@ static int nr_device_event(struct notifier_block *this, unsigned long event, voi
*/
static
void
nr_insert_socket
(
struct
sock
*
sk
)
{
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
nr_list_lock
);
sk
->
next
=
nr_list
;
nr_list
=
sk
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_list_lock
);
}
/*
...
...
@@ -196,21 +169,18 @@ static void nr_insert_socket(struct sock *sk)
*/
static
struct
sock
*
nr_find_listener
(
ax25_address
*
addr
)
{
unsigned
long
flags
;
struct
sock
*
s
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
nr_list_lock
);
for
(
s
=
nr_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
if
(
!
ax25cmp
(
&
nr_sk
(
s
)
->
source_addr
,
addr
)
&&
s
->
state
==
TCP_LISTEN
)
{
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_list_lock
);
return
s
;
}
}
spin_unlock_bh
(
&
nr_list_lock
);
restore_flags
(
flags
);
return
NULL
;
}
...
...
@@ -220,21 +190,17 @@ static struct sock *nr_find_listener(ax25_address *addr)
static
struct
sock
*
nr_find_socket
(
unsigned
char
index
,
unsigned
char
id
)
{
struct
sock
*
s
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
nr_list_lock
);
for
(
s
=
nr_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
nr_cb
*
nr
=
nr_sk
(
s
);
if
(
nr
->
my_index
==
index
&&
nr
->
my_id
==
id
)
{
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_list_lock
);
return
s
;
}
}
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_list_lock
);
return
NULL
;
}
...
...
@@ -242,25 +208,22 @@ static struct sock *nr_find_socket(unsigned char index, unsigned char id)
/*
* Find a connected NET/ROM socket given their circuit IDs.
*/
static
struct
sock
*
nr_find_peer
(
unsigned
char
index
,
unsigned
char
id
,
ax25_address
*
dest
)
static
struct
sock
*
nr_find_peer
(
unsigned
char
index
,
unsigned
char
id
,
ax25_address
*
dest
)
{
struct
sock
*
s
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
nr_list_lock
);
for
(
s
=
nr_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
nr_cb
*
nr
=
nr_sk
(
s
);
if
(
nr
->
your_index
==
index
&&
nr
->
your_id
==
id
&&
!
ax25cmp
(
&
nr
->
dest_addr
,
dest
))
{
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_list_lock
);
return
s
;
}
}
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_list_lock
);
return
NULL
;
}
...
...
@@ -301,17 +264,16 @@ static void nr_destroy_timer(unsigned long data)
}
/*
* This is called from user mode and the timers. Thus it protects itself
against
*
interrupt users but doesn't worry about being called during work.
*
Once it is removed from the queue no interrupt or bottom half will
* touch it and we are (fairly 8-) ) safe.
* This is called from user mode and the timers. Thus it protects itself
*
against interrupt users but doesn't worry about being called during
*
work. Once it is removed from the queue no interrupt or bottom half
*
will
touch it and we are (fairly 8-) ) safe.
*/
void
nr_destroy_socket
(
struct
sock
*
sk
)
/* Not static as it's used by the timer */
void
nr_destroy_socket
(
struct
sock
*
sk
)
{
struct
sk_buff
*
skb
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
(
);
nr_remove_socket
(
sk
);
nr_stop_heartbeat
(
sk
);
nr_stop_t1timer
(
sk
);
...
...
@@ -319,7 +281,6 @@ void nr_destroy_socket(struct sock *sk) /* Not static as it's used by the timer
nr_stop_t4timer
(
sk
);
nr_stop_idletimer
(
sk
);
nr_remove_socket
(
sk
);
nr_clear_queues
(
sk
);
/* Flush the queues */
while
((
skb
=
skb_dequeue
(
&
sk
->
receive_queue
))
!=
NULL
)
{
...
...
@@ -342,8 +303,6 @@ void nr_destroy_socket(struct sock *sk) /* Not static as it's used by the timer
}
else
{
nr_free_sock
(
sk
);
}
restore_flags
(
flags
);
}
/*
...
...
@@ -567,7 +526,6 @@ static int nr_release(struct socket *sock)
nr
=
nr_sk
(
sk
);
switch
(
nr
->
state
)
{
case
NR_STATE_0
:
case
NR_STATE_1
:
case
NR_STATE_2
:
...
...
@@ -732,78 +690,98 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
if
(
sk
->
state
!=
TCP_ESTABLISHED
&&
(
flags
&
O_NONBLOCK
))
return
-
EINPROGRESS
;
cli
();
/* To avoid races on the sleep */
/*
* A Connect Ack with Choke or timeout or failed routing will go to closed.
* A Connect Ack with Choke or timeout or failed routing will go to
* closed.
*/
while
(
sk
->
state
==
TCP_SYN_SENT
)
{
interruptible_sleep_on
(
sk
->
sleep
);
if
(
signal_pending
(
current
))
{
sti
();
if
(
sk
->
state
==
TCP_SYN_SENT
)
{
struct
task_struct
*
tsk
=
current
;
DECLARE_WAITQUEUE
(
wait
,
tsk
);
add_wait_queue
(
sk
->
sleep
,
&
wait
);
for
(;;)
{
set_current_state
(
TASK_INTERRUPTIBLE
);
if
(
sk
->
state
!=
TCP_SYN_SENT
)
break
;
if
(
!
signal_pending
(
tsk
))
{
schedule
();
continue
;
}
return
-
ERESTARTSYS
;
}
current
->
state
=
TASK_RUNNING
;
remove_wait_queue
(
sk
->
sleep
,
&
wait
);
}
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
{
sti
();
sock
->
state
=
SS_UNCONNECTED
;
return
sock_error
(
sk
);
/* Always set at this point */
}
sock
->
state
=
SS_CONNECTED
;
sti
();
return
0
;
}
static
int
nr_accept
(
struct
socket
*
sock
,
struct
socket
*
newsock
,
int
flags
)
{
struct
sock
*
sk
;
struct
sock
*
newsk
;
struct
task_struct
*
tsk
=
current
;
DECLARE_WAITQUEUE
(
wait
,
tsk
)
;
struct
sk_buff
*
skb
;
struct
sock
*
newsk
;
struct
sock
*
sk
;
int
err
=
0
;
if
((
sk
=
sock
->
sk
)
==
NULL
)
return
-
EINVAL
;
if
(
sk
->
type
!=
SOCK_SEQPACKET
)
return
-
EOPNOTSUPP
;
lock_sock
(
sk
);
if
(
sk
->
type
!=
SOCK_SEQPACKET
)
{
err
=
-
EOPNOTSUPP
;
goto
out
;
}
if
(
sk
->
state
!=
TCP_LISTEN
)
return
-
EINVAL
;
if
(
sk
->
state
!=
TCP_LISTEN
)
{
err
=
-
EINVAL
;
goto
out
;
}
/*
* The write queue this time is holding sockets ready to use
* hooked into the SABM we saved
*/
do
{
cli
();
if
((
skb
=
skb_dequeue
(
&
sk
->
receive_queue
))
==
NULL
)
{
if
(
flags
&
O_NONBLOCK
)
{
sti
();
add_wait_queue
(
sk
->
sleep
,
&
wait
);
for
(;;)
{
skb
=
skb_dequeue
(
&
sk
->
receive_queue
);
if
(
skb
)
break
;
current
->
state
=
TASK_INTERRUPTIBLE
;
release_sock
(
sk
);
if
(
flags
&
O_NONBLOCK
)
return
-
EWOULDBLOCK
;
if
(
!
signal_pending
(
tsk
))
{
schedule
();
lock_sock
(
sk
);
continue
;
}
interruptible_sleep_on
(
sk
->
sleep
);
if
(
signal_pending
(
current
))
{
sti
();
return
-
ERESTARTSYS
;
}
}
}
while
(
skb
==
NULL
);
current
->
state
=
TASK_RUNNING
;
remove_wait_queue
(
sk
->
sleep
,
&
wait
);
newsk
=
skb
->
sk
;
newsk
->
pair
=
NULL
;
newsk
->
socket
=
newsock
;
newsk
->
sleep
=
&
newsock
->
wait
;
sti
();
/* Now attach up the new socket */
kfree_skb
(
skb
);
sk
->
ack_backlog
--
;
newsock
->
sk
=
newsk
;
return
0
;
out:
return
err
;
}
static
int
nr_getname
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
...
...
@@ -1174,7 +1152,6 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
return
dev_ioctl
(
cmd
,
(
void
*
)
arg
);
}
/*NOTREACHED*/
return
0
;
}
...
...
@@ -1187,7 +1164,7 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length)
off_t
pos
=
0
;
off_t
begin
=
0
;
cli
(
);
spin_lock_bh
(
&
nr_list_lock
);
len
+=
sprintf
(
buffer
,
"user_addr dest_node src_node dev my your st vs vr va t1 t2 t4 idle n2 wnd Snd-Q Rcv-Q inode
\n
"
);
...
...
@@ -1240,14 +1217,15 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length)
break
;
}
s
ti
(
);
s
pin_unlock_bh
(
&
nr_list_lock
);
*
start
=
buffer
+
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
if
(
len
>
length
)
len
=
length
;
if
(
len
>
length
)
len
=
length
;
return
(
len
)
;
return
len
;
}
static
struct
net_proto_family
nr_family_ops
=
{
...
...
@@ -1255,7 +1233,7 @@ static struct net_proto_family nr_family_ops = {
.
create
=
nr_create
,
};
static
struct
proto_ops
SOCKOPS_WRAPPED
(
nr_proto_ops
)
=
{
static
struct
proto_ops
nr_proto_ops
=
{
.
family
=
PF_NETROM
,
.
release
=
nr_release
,
...
...
@@ -1276,11 +1254,8 @@ static struct proto_ops SOCKOPS_WRAPPED(nr_proto_ops) = {
.
sendpage
=
sock_no_sendpage
,
};
#include <linux/smp_lock.h>
SOCKOPS_WRAP
(
nr_proto
,
PF_NETROM
);
static
struct
notifier_block
nr_dev_notifier
=
{
.
notifier_call
=
nr_device_event
,
.
notifier_call
=
nr_device_event
,
};
static
struct
net_device
*
dev_nr
;
...
...
net/netrom/nr_dev.c
View file @
a4041f6f
/*
* NET/ROM release 007
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* NET/ROM 001 Jonathan(G4KLX) Cloned from loopback.c
* NET/ROM 002 Steve Whitehouse(GW7RRM) fixed the set_mac_address
* NET/ROM 003 Jonathan(G4KLX) Put nr_rebuild_header into line with
* ax25_rebuild_header
* NET/ROM 004 Jonathan(G4KLX) Callsign registration with AX.25.
* NET/ROM 006 Hans(PE1AYX) Fixed interface to IP layer.
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
...
...
net/netrom/nr_in.c
View file @
a4041f6f
/*
* NET/ROM release 007
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_in.c
* NET/ROM 003 Jonathan(G4KLX) Added NET/ROM fragment reception.
* Darryl(G7LED) Added missing INFO with NAK case, optimized
* INFOACK handling, removed reconnect on error.
* NET/ROM 006 Jonathan(G4KLX) Hdrincl removal changes.
* NET/ROM 007 Jonathan(G4KLX) New timer architecture.
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
...
...
@@ -88,10 +71,10 @@ static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
* The handling of the timer(s) is in file nr_timer.c.
* Handling of state 0 and connection release is in netrom.c.
*/
static
int
nr_state1_machine
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
,
int
frametype
)
static
int
nr_state1_machine
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
,
int
frametype
)
{
switch
(
frametype
)
{
case
NR_CONNACK
:
{
nr_cb
*
nr
=
nr_sk
(
sk
);
...
...
@@ -128,10 +111,10 @@ static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype
* The handling of the timer(s) is in file nr_timer.c
* Handling of state 0 and connection release is in netrom.c.
*/
static
int
nr_state2_machine
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
,
int
frametype
)
static
int
nr_state2_machine
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
,
int
frametype
)
{
switch
(
frametype
)
{
case
NR_CONNACK
|
NR_CHOKE_FLAG
:
nr_disconnect
(
sk
,
ECONNRESET
);
break
;
...
...
@@ -168,7 +151,6 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
ns
=
skb
->
data
[
17
];
switch
(
frametype
)
{
case
NR_CONNREQ
:
nr_write_internal
(
sk
,
NR_CONNACK
);
break
;
...
...
net/netrom/nr_loopback.c
View file @
a4041f6f
/*
* NET/ROM release 007
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* NET/ROM 007 Tomi(OH2BNS) Created this file.
* Small change in nr_loopback_queue().
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Copyright Tomi Manninen OH2BNS (oh2bns@sral.fi)
*/
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/timer.h>
...
...
net/netrom/nr_out.c
View file @
a4041f6f
/*
* NET/ROM release 007
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_out.c
* NET/ROM 003 Jonathan(G4KLX) Added NET/ROM fragmentation.
* Darryl(G7LED) Fixed NAK, to give out correct reponse.
* NET/ROM 007 Jonathan(G4KLX) New timer architecture.
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
...
...
@@ -196,7 +187,7 @@ void nr_kick(struct sock *sk)
void
nr_transmit_buffer
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
)
{
nr_cb
*
nr
=
nr
;
nr_cb
*
nr
=
nr
_sk
(
sk
)
;
unsigned
char
*
dptr
;
/*
...
...
net/netrom/nr_route.c
View file @
a4041f6f
/*
* NET/ROM release 007
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* NET/ROM 001 Jonathan(G4KLX) First attempt.
* NET/ROM 003 Jonathan(G4KLX) Use SIOCADDRT/SIOCDELRT ioctl values
* for NET/ROM routes.
* Use '*' for a blank mnemonic in /proc/net/nr_nodes.
* Change default quality for new neighbour when same
* as node callsign.
* Alan Cox(GW4PTS) Added the firewall hooks.
* NET/ROM 006 Jonathan(G4KLX) Added the setting of digipeated neighbours.
* Tomi(OH2BNS) Routing quality and link failure changes.
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright Tomi Manninen OH2BNS (oh2bns@sral.fi)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
...
...
@@ -47,12 +34,15 @@
#include <linux/notifier.h>
#include <linux/netfilter.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <net/netrom.h>
static
unsigned
int
nr_neigh_no
=
1
;
static
struct
nr_node
*
nr_node_list
;
static
spinlock_t
nr_node_lock
;
static
struct
nr_neigh
*
nr_neigh_list
;
static
spinlock_t
nr_neigh_lock
;
static
void
nr_remove_neigh
(
struct
nr_neigh
*
);
...
...
@@ -66,7 +56,6 @@ static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax2
struct
nr_node
*
nr_node
;
struct
nr_neigh
*
nr_neigh
;
struct
nr_route
nr_route
;
unsigned
long
flags
;
int
i
,
found
;
if
(
nr_dev_get
(
nr
)
!=
NULL
)
/* Can't add routes to ourself */
...
...
@@ -124,13 +113,10 @@ static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax2
memcpy
(
nr_neigh
->
digipeat
,
ax25_digi
,
sizeof
(
ax25_digi
));
}
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
nr_neigh_lock
);
nr_neigh
->
next
=
nr_neigh_list
;
nr_neigh_list
=
nr_neigh
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_neigh_lock
);
}
if
(
quality
!=
0
&&
ax25cmp
(
nr
,
ax25
)
==
0
&&
!
nr_neigh
->
locked
)
...
...
@@ -150,13 +136,10 @@ static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax2
nr_node
->
routes
[
0
].
obs_count
=
obs_count
;
nr_node
->
routes
[
0
].
neighbour
=
nr_neigh
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
nr_node_lock
);
nr_node
->
next
=
nr_node_list
;
nr_node_list
=
nr_node
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_node_lock
);
nr_neigh
->
count
++
;
...
...
@@ -220,9 +203,14 @@ static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax2
}
if
(
nr_node
->
routes
[
2
].
quality
>
nr_node
->
routes
[
1
].
quality
)
{
switch
(
nr_node
->
which
)
{
case
1
:
nr_node
->
which
=
2
;
break
;
case
2
:
nr_node
->
which
=
1
;
break
;
default:
break
;
case
1
:
nr_node
->
which
=
2
;
break
;
case
2
:
nr_node
->
which
=
1
;
break
;
default:
break
;
}
nr_route
=
nr_node
->
routes
[
1
];
nr_node
->
routes
[
1
]
=
nr_node
->
routes
[
2
];
...
...
@@ -231,8 +219,12 @@ static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax2
case
2
:
if
(
nr_node
->
routes
[
1
].
quality
>
nr_node
->
routes
[
0
].
quality
)
{
switch
(
nr_node
->
which
)
{
case
0
:
nr_node
->
which
=
1
;
break
;
case
1
:
nr_node
->
which
=
0
;
break
;
case
0
:
nr_node
->
which
=
1
;
break
;
case
1
:
nr_node
->
which
=
0
;
break
;
default:
break
;
}
nr_route
=
nr_node
->
routes
[
0
];
...
...
@@ -257,14 +249,11 @@ static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax2
static
void
nr_remove_node
(
struct
nr_node
*
nr_node
)
{
struct
nr_node
*
s
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
nr_node_lock
);
if
((
s
=
nr_node_list
)
==
nr_node
)
{
nr_node_list
=
nr_node
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_node_lock
);
kfree
(
nr_node
);
return
;
}
...
...
@@ -272,7 +261,7 @@ static void nr_remove_node(struct nr_node *nr_node)
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
if
(
s
->
next
==
nr_node
)
{
s
->
next
=
nr_node
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_node_lock
);
kfree
(
nr_node
);
return
;
}
...
...
@@ -280,20 +269,17 @@ static void nr_remove_node(struct nr_node *nr_node)
s
=
s
->
next
;
}
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_node_lock
);
}
static
void
nr_remove_neigh
(
struct
nr_neigh
*
nr_neigh
)
{
struct
nr_neigh
*
s
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
nr_neigh_lock
);
if
((
s
=
nr_neigh_list
)
==
nr_neigh
)
{
nr_neigh_list
=
nr_neigh
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_neigh_lock
);
if
(
nr_neigh
->
digipeat
!=
NULL
)
kfree
(
nr_neigh
->
digipeat
);
kfree
(
nr_neigh
);
...
...
@@ -303,7 +289,7 @@ static void nr_remove_neigh(struct nr_neigh *nr_neigh)
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
if
(
s
->
next
==
nr_neigh
)
{
s
->
next
=
nr_neigh
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_neigh_lock
);
if
(
nr_neigh
->
digipeat
!=
NULL
)
kfree
(
nr_neigh
->
digipeat
);
kfree
(
nr_neigh
);
...
...
@@ -312,8 +298,7 @@ static void nr_remove_neigh(struct nr_neigh *nr_neigh)
s
=
s
->
next
;
}
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_neigh_lock
);
}
/*
...
...
@@ -330,13 +315,15 @@ static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct n
if
(
ax25cmp
(
callsign
,
&
nr_node
->
callsign
)
==
0
)
break
;
if
(
nr_node
==
NULL
)
return
-
EINVAL
;
if
(
nr_node
==
NULL
)
return
-
EINVAL
;
for
(
nr_neigh
=
nr_neigh_list
;
nr_neigh
!=
NULL
;
nr_neigh
=
nr_neigh
->
next
)
if
(
ax25cmp
(
neighbour
,
&
nr_neigh
->
callsign
)
==
0
&&
nr_neigh
->
dev
==
dev
)
break
;
if
(
nr_neigh
==
NULL
)
return
-
EINVAL
;
if
(
nr_neigh
==
NULL
)
return
-
EINVAL
;
for
(
i
=
0
;
i
<
nr_node
->
count
;
i
++
)
{
if
(
nr_node
->
routes
[
i
].
neighbour
==
nr_neigh
)
{
...
...
@@ -373,7 +360,6 @@ static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct n
static
int
nr_add_neigh
(
ax25_address
*
callsign
,
ax25_digi
*
ax25_digi
,
struct
net_device
*
dev
,
unsigned
int
quality
)
{
struct
nr_neigh
*
nr_neigh
;
unsigned
long
flags
;
for
(
nr_neigh
=
nr_neigh_list
;
nr_neigh
!=
NULL
;
nr_neigh
=
nr_neigh
->
next
)
{
if
(
ax25cmp
(
callsign
,
&
nr_neigh
->
callsign
)
==
0
&&
nr_neigh
->
dev
==
dev
)
{
...
...
@@ -404,13 +390,10 @@ static int nr_add_neigh(ax25_address *callsign, ax25_digi *ax25_digi, struct net
memcpy
(
nr_neigh
->
digipeat
,
ax25_digi
,
sizeof
(
ax25_digi
));
}
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
nr_neigh_lock
);
nr_neigh
->
next
=
nr_neigh_list
;
nr_neigh_list
=
nr_neigh
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_neigh_lock
);
return
0
;
}
...
...
@@ -457,7 +440,6 @@ static int nr_dec_obs(void)
for
(
i
=
0
;
i
<
s
->
count
;
i
++
)
{
switch
(
s
->
routes
[
i
].
obs_count
)
{
case
0
:
/* A locked entry */
break
;
...
...
@@ -622,7 +604,6 @@ int nr_rt_ioctl(unsigned int cmd, void *arg)
struct
net_device
*
dev
;
switch
(
cmd
)
{
case
SIOCADDRT
:
if
(
copy_from_user
(
&
nr_route
,
arg
,
sizeof
(
struct
nr_route_struct
)))
return
-
EFAULT
;
...
...
@@ -758,8 +739,7 @@ int nr_nodes_get_info(char *buffer, char **start, off_t offset, int length)
off_t
begin
=
0
;
int
i
;
cli
();
spin_lock_bh
(
&
nr_node_lock
);
len
+=
sprintf
(
buffer
,
"callsign mnemonic w n qual obs neigh qual obs neigh qual obs neigh
\n
"
);
for
(
nr_node
=
nr_node_list
;
nr_node
!=
NULL
;
nr_node
=
nr_node
->
next
)
{
...
...
@@ -788,8 +768,7 @@ int nr_nodes_get_info(char *buffer, char **start, off_t offset, int length)
if
(
pos
>
offset
+
length
)
break
;
}
sti
();
spin_unlock_bh
(
&
nr_node_lock
);
*
start
=
buffer
+
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
...
...
@@ -807,8 +786,7 @@ int nr_neigh_get_info(char *buffer, char **start, off_t offset, int length)
off_t
begin
=
0
;
int
i
;
cli
();
spin_lock_bh
(
&
nr_neigh_lock
);
len
+=
sprintf
(
buffer
,
"addr callsign dev qual lock count failed digipeaters
\n
"
);
for
(
nr_neigh
=
nr_neigh_list
;
nr_neigh
!=
NULL
;
nr_neigh
=
nr_neigh
->
next
)
{
...
...
@@ -839,7 +817,7 @@ int nr_neigh_get_info(char *buffer, char **start, off_t offset, int length)
break
;
}
s
ti
(
);
s
pin_unlock_bh
(
&
nr_neigh_lock
);
*
start
=
buffer
+
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
...
...
net/netrom/nr_subr.c
View file @
a4041f6f
/*
* NET/ROM release 007
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_subr.c
* NET/ROM 003 Jonathan(G4KLX) Added G8BPQ NET/ROM extensions.
* NET/ROM 007 Jonathan(G4KLX) New timer architecture.
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
...
...
@@ -165,7 +156,6 @@ void nr_write_internal(struct sock *sk, int frametype)
dptr
=
skb_put
(
skb
,
skb_tailroom
(
skb
));
switch
(
frametype
&
0x0F
)
{
case
NR_CONNREQ
:
timeout
=
nr
->
t1
/
HZ
;
*
dptr
++
=
nr
->
my_index
;
...
...
net/netrom/nr_timer.c
View file @
a4041f6f
/*
* NET/ROM release 007
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_timer.c
* NET/ROM 007 Jonathan(G4KLX) New timer architecture.
* Implemented idle timer.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
...
...
@@ -144,8 +136,8 @@ static void nr_heartbeat_expiry(unsigned long param)
struct
sock
*
sk
=
(
struct
sock
*
)
param
;
nr_cb
*
nr
=
nr_sk
(
sk
);
bh_lock_sock
(
sk
);
switch
(
nr
->
state
)
{
case
NR_STATE_0
:
/* Magic here: If we listen() and a new link dies before it
is accepted() it isn't 'dead' so doesn't get removed. */
...
...
@@ -171,6 +163,7 @@ static void nr_heartbeat_expiry(unsigned long param)
}
nr_start_heartbeat
(
sk
);
bh_unlock_sock
(
sk
);
}
static
void
nr_t2timer_expiry
(
unsigned
long
param
)
...
...
@@ -178,17 +171,21 @@ static void nr_t2timer_expiry(unsigned long param)
struct
sock
*
sk
=
(
struct
sock
*
)
param
;
nr_cb
*
nr
=
nr_sk
(
sk
);
bh_lock_sock
(
sk
);
if
(
nr
->
condition
&
NR_COND_ACK_PENDING
)
{
nr
->
condition
&=
~
NR_COND_ACK_PENDING
;
nr_enquiry_response
(
sk
);
}
bh_unlock_sock
(
sk
);
}
static
void
nr_t4timer_expiry
(
unsigned
long
param
)
{
struct
sock
*
sk
=
(
struct
sock
*
)
param
;
bh_lock_sock
(
sk
);
nr_sk
(
sk
)
->
condition
&=
~
NR_COND_PEER_RX_BUSY
;
bh_unlock_sock
(
sk
);
}
static
void
nr_idletimer_expiry
(
unsigned
long
param
)
...
...
@@ -196,6 +193,8 @@ static void nr_idletimer_expiry(unsigned long param)
struct
sock
*
sk
=
(
struct
sock
*
)
param
;
nr_cb
*
nr
=
nr_sk
(
sk
);
bh_lock_sock
(
sk
);
nr_clear_queues
(
sk
);
nr
->
n2count
=
0
;
...
...
@@ -214,6 +213,7 @@ static void nr_idletimer_expiry(unsigned long param)
sk
->
state_change
(
sk
);
sk
->
dead
=
1
;
bh_unlock_sock
(
sk
);
}
static
void
nr_t1timer_expiry
(
unsigned
long
param
)
...
...
@@ -221,8 +221,8 @@ static void nr_t1timer_expiry(unsigned long param)
struct
sock
*
sk
=
(
struct
sock
*
)
param
;
nr_cb
*
nr
=
nr_sk
(
sk
);
bh_lock_sock
(
sk
);
switch
(
nr
->
state
)
{
case
NR_STATE_1
:
if
(
nr
->
n2count
==
nr
->
n2
)
{
nr_disconnect
(
sk
,
ETIMEDOUT
);
...
...
@@ -255,4 +255,5 @@ static void nr_t1timer_expiry(unsigned long param)
}
nr_start_t1timer
(
sk
);
bh_unlock_sock
(
sk
);
}
net/netrom/sysctl_net_netrom.c
View file @
a4041f6f
/* -*- linux-c -*-
* sysctl_net_netrom.c: sysctl interface to net NET/ROM subsystem.
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Begun April 1, 1996, Mike Shaver.
* Added /proc/sys/net/netrom directory entry (empty =) ). [MS]
* Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com)
*/
#include <linux/mm.h>
#include <linux/sysctl.h>
#include <linux/init.h>
...
...
net/rose/af_rose.c
View file @
a4041f6f
/*
* ROSE release 003
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from af_netrom.c.
* Alan(GW4PTS) Hacked up for newer API stuff
* Terry (VK2KTJ) Added support for variable length
* address masks.
* ROSE 002 Jonathan(G4KLX) Changed hdrincl to qbitincl.
* Added random number facilities entry.
* Variable number of ROSE devices.
* ROSE 003 Jonathan(G4KLX) New timer architecture.
* Implemented idle timer.
* Added use count to neighbour.
* Tomi(OH2BNS) Fixed rose_getname().
* Arnaldo C. Melo s/suser/capable/ + micro cleanups
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright (C) Terry Dawson VK2KTJ (terry@animats.net)
* Copyright (C) Tomi Manninen OH2BNS (oh2bns@sral.fi)
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
...
...
@@ -33,6 +18,7 @@
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/sockios.h>
...
...
@@ -47,7 +33,7 @@
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/fcntl.h>
#include <linux/termios.h>
/* For TIOCINQ/OUTQ */
#include <linux/termios.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/notifier.h>
...
...
@@ -71,6 +57,7 @@ int sysctl_rose_maximum_vcs = ROSE_DEFAULT_MAXVC;
int
sysctl_rose_window_size
=
ROSE_DEFAULT_WINDOW_SIZE
;
static
struct
sock
*
rose_list
;
static
spinlock_t
rose_list_lock
=
SPIN_LOCK_UNLOCKED
;
static
struct
proto_ops
rose_proto_ops
;
...
...
@@ -173,27 +160,24 @@ decmod: MOD_DEC_USE_COUNT;
static
void
rose_remove_socket
(
struct
sock
*
sk
)
{
struct
sock
*
s
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
rose_list_lock
);
if
((
s
=
rose_list
)
==
sk
)
{
rose_list
=
s
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
rose_list_lock
);
return
;
}
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
if
(
s
->
next
==
sk
)
{
s
->
next
=
sk
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
rose_list_lock
);
return
;
}
s
=
s
->
next
;
}
restore_flags
(
flags
);
spin_unlock_bh
(
&
rose_list_lock
);
}
/*
...
...
@@ -204,6 +188,7 @@ void rose_kill_by_neigh(struct rose_neigh *neigh)
{
struct
sock
*
s
;
spin_lock_bh
(
&
rose_list_lock
);
for
(
s
=
rose_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
rose_cb
*
rose
=
rose_sk
(
s
);
...
...
@@ -213,6 +198,7 @@ void rose_kill_by_neigh(struct rose_neigh *neigh)
rose
->
neighbour
=
NULL
;
}
}
spin_unlock_bh
(
&
rose_list_lock
);
}
/*
...
...
@@ -222,6 +208,7 @@ static void rose_kill_by_device(struct net_device *dev)
{
struct
sock
*
s
;
spin_lock_bh
(
&
rose_list_lock
);
for
(
s
=
rose_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
rose_cb
*
rose
=
rose_sk
(
s
);
...
...
@@ -231,12 +218,14 @@ static void rose_kill_by_device(struct net_device *dev)
rose
->
device
=
NULL
;
}
}
spin_unlock_bh
(
&
rose_list_lock
);
}
/*
* Handle device status changes.
*/
static
int
rose_device_event
(
struct
notifier_block
*
this
,
unsigned
long
event
,
void
*
ptr
)
static
int
rose_device_event
(
struct
notifier_block
*
this
,
unsigned
long
event
,
void
*
ptr
)
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
ptr
;
...
...
@@ -261,14 +250,11 @@ static int rose_device_event(struct notifier_block *this, unsigned long event, v
*/
static
void
rose_insert_socket
(
struct
sock
*
sk
)
{
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
rose_list_lock
);
sk
->
next
=
rose_list
;
rose_list
=
sk
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
rose_list_lock
);
}
/*
...
...
@@ -277,18 +263,16 @@ static void rose_insert_socket(struct sock *sk)
*/
static
struct
sock
*
rose_find_listener
(
rose_address
*
addr
,
ax25_address
*
call
)
{
unsigned
long
flags
;
struct
sock
*
s
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
rose_list_lock
);
for
(
s
=
rose_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
rose_cb
*
rose
=
rose_sk
(
s
);
if
(
!
rosecmp
(
&
rose
->
source_addr
,
addr
)
&&
!
ax25cmp
(
&
rose
->
source_call
,
call
)
&&
!
rose
->
source_ndigis
&&
s
->
state
==
TCP_LISTEN
)
{
restore_flags
(
flags
);
spin_unlock_bh
(
&
rose_list_lock
);
return
s
;
}
}
...
...
@@ -299,12 +283,12 @@ static struct sock *rose_find_listener(rose_address *addr, ax25_address *call)
if
(
!
rosecmp
(
&
rose
->
source_addr
,
addr
)
&&
!
ax25cmp
(
&
rose
->
source_call
,
&
null_ax25_address
)
&&
s
->
state
==
TCP_LISTEN
)
{
restore_flags
(
flags
);
spin_unlock_bh
(
&
rose_list_lock
);
return
s
;
}
}
spin_unlock_bh
(
&
rose_list_lock
);
restore_flags
(
flags
);
return
NULL
;
}
...
...
@@ -314,20 +298,17 @@ static struct sock *rose_find_listener(rose_address *addr, ax25_address *call)
struct
sock
*
rose_find_socket
(
unsigned
int
lci
,
struct
rose_neigh
*
neigh
)
{
struct
sock
*
s
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
rose_list_lock
);
for
(
s
=
rose_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
rose_cb
*
rose
=
rose_sk
(
s
);
if
(
rose
->
lci
==
lci
&&
rose
->
neighbour
==
neigh
)
{
restore_flags
(
flags
);
spin_unlock_bh
(
&
rose_list_lock
);
return
s
;
}
}
restore_flags
(
flags
);
spin_unlock_bh
(
&
rose_list_lock
);
return
NULL
;
}
...
...
@@ -366,23 +347,20 @@ static void rose_destroy_timer(unsigned long data)
}
/*
* This is called from user mode and the timers. Thus it protects itself
against
*
interrupt users but doesn't worry about being called during work.
*
Once it is removed from the queue no interrupt or bottom half will
* touch it and we are (fairly 8-) ) safe.
* This is called from user mode and the timers. Thus it protects itself
*
against interrupt users but doesn't worry about being called during
*
work. Once it is removed from the queue no interrupt or bottom half
*
will
touch it and we are (fairly 8-) ) safe.
*/
void
rose_destroy_socket
(
struct
sock
*
sk
)
/* Not static as it's used by the timer */
void
rose_destroy_socket
(
struct
sock
*
sk
)
{
struct
sk_buff
*
skb
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
rose_remove_socket
(
sk
);
rose_stop_heartbeat
(
sk
);
rose_stop_idletimer
(
sk
);
rose_stop_timer
(
sk
);
rose_remove_socket
(
sk
);
rose_clear_queues
(
sk
);
/* Flush the queues */
while
((
skb
=
skb_dequeue
(
&
sk
->
receive_queue
))
!=
NULL
)
{
...
...
@@ -405,8 +383,6 @@ void rose_destroy_socket(struct sock *sk) /* Not static as it's used by the time
}
else
{
rose_free_sock
(
sk
);
}
restore_flags
(
flags
);
}
/*
...
...
@@ -647,7 +623,6 @@ static int rose_release(struct socket *sock)
rose
=
rose_sk
(
sk
);
switch
(
rose
->
state
)
{
case
ROSE_STATE_0
:
rose_disconnect
(
sk
,
0
,
-
1
,
-
1
);
rose_destroy_socket
(
sk
);
...
...
@@ -813,7 +788,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
rose
->
dest_addr
=
addr
->
srose_addr
;
rose
->
dest_call
=
addr
->
srose_call
;
rose
->
rand
=
((
int
)
rose
&
0xFFFF
)
+
rose
->
lci
;
rose
->
rand
=
((
long
)
rose
&
0xFFFF
)
+
rose
->
lci
;
rose
->
dest_ndigis
=
addr
->
srose_ndigis
;
if
(
addr_len
==
sizeof
(
struct
full_sockaddr_rose
))
{
...
...
@@ -842,71 +817,90 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
if
(
sk
->
state
!=
TCP_ESTABLISHED
&&
(
flags
&
O_NONBLOCK
))
return
-
EINPROGRESS
;
cli
();
/* To avoid races on the sleep */
/*
* A Connect Ack with Choke or timeout or failed routing will go to closed.
* A Connect Ack with Choke or timeout or failed routing will go to
* closed.
*/
while
(
sk
->
state
==
TCP_SYN_SENT
)
{
interruptible_sleep_on
(
sk
->
sleep
);
if
(
signal_pending
(
current
))
{
sti
();
if
(
sk
->
state
==
TCP_SYN_SENT
)
{
struct
task_struct
*
tsk
=
current
;
DECLARE_WAITQUEUE
(
wait
,
tsk
);
add_wait_queue
(
sk
->
sleep
,
&
wait
);
for
(;;)
{
set_current_state
(
TASK_INTERRUPTIBLE
);
if
(
sk
->
state
!=
TCP_SYN_SENT
)
break
;
if
(
!
signal_pending
(
tsk
))
{
schedule
();
continue
;
}
return
-
ERESTARTSYS
;
}
current
->
state
=
TASK_RUNNING
;
remove_wait_queue
(
sk
->
sleep
,
&
wait
);
}
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
{
sti
();
sock
->
state
=
SS_UNCONNECTED
;
return
sock_error
(
sk
);
/* Always set at this point */
}
sock
->
state
=
SS_CONNECTED
;
sti
();
return
0
;
}
static
int
rose_accept
(
struct
socket
*
sock
,
struct
socket
*
newsock
,
int
flags
)
{
struct
sock
*
sk
;
struct
sock
*
newsk
;
struct
task_struct
*
tsk
=
current
;
DECLARE_WAITQUEUE
(
wait
,
tsk
)
;
struct
sk_buff
*
skb
;
struct
sock
*
newsk
;
struct
sock
*
sk
;
int
err
=
0
;
if
((
sk
=
sock
->
sk
)
==
NULL
)
return
-
EINVAL
;
if
(
sk
->
type
!=
SOCK_SEQPACKET
)
return
-
EOPNOTSUPP
;
lock_sock
(
sk
);
if
(
sk
->
type
!=
SOCK_SEQPACKET
)
{
err
=
-
EOPNOTSUPP
;
goto
out
;
}
if
(
sk
->
state
!=
TCP_LISTEN
)
return
-
EINVAL
;
if
(
sk
->
state
!=
TCP_LISTEN
)
{
err
=
-
EINVAL
;
goto
out
;
}
/*
* The write queue this time is holding sockets ready to use
* hooked into the SABM we saved
*/
do
{
cli
();
if
((
skb
=
skb_dequeue
(
&
sk
->
receive_queue
))
==
NULL
)
{
if
(
flags
&
O_NONBLOCK
)
{
sti
();
add_wait_queue
(
sk
->
sleep
,
&
wait
);
for
(;;)
{
skb
=
skb_dequeue
(
&
sk
->
receive_queue
);
if
(
skb
)
break
;
current
->
state
=
TASK_INTERRUPTIBLE
;
release_sock
(
sk
);
if
(
flags
&
O_NONBLOCK
)
return
-
EWOULDBLOCK
;
if
(
!
signal_pending
(
tsk
))
{
schedule
();
lock_sock
(
sk
);
continue
;
}
interruptible_sleep_on
(
sk
->
sleep
);
if
(
signal_pending
(
current
))
{
sti
();
return
-
ERESTARTSYS
;
}
}
}
while
(
skb
==
NULL
);
current
->
state
=
TASK_RUNNING
;
remove_wait_queue
(
sk
->
sleep
,
&
wait
);
newsk
=
skb
->
sk
;
newsk
->
pair
=
NULL
;
newsk
->
socket
=
newsock
;
newsk
->
sleep
=
&
newsock
->
wait
;
sti
();
/* Now attach up the new socket */
skb
->
sk
=
NULL
;
...
...
@@ -914,7 +908,10 @@ static int rose_accept(struct socket *sock, struct socket *newsock, int flags)
sk
->
ack_backlog
--
;
newsock
->
sk
=
newsk
;
return
0
;
out:
release_sock
(
sk
);
return
err
;
}
static
int
rose_getname
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
...
...
@@ -1304,7 +1301,8 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case
SIOCADDRT
:
case
SIOCDELRT
:
case
SIOCRSCLRRT
:
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
return
rose_rt_ioctl
(
cmd
,
(
void
*
)
arg
);
case
SIOCRSGCAUSE
:
{
...
...
@@ -1353,7 +1351,6 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
return
dev_ioctl
(
cmd
,
(
void
*
)
arg
);
}
/*NOTREACHED*/
return
0
;
}
...
...
@@ -1366,7 +1363,7 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length)
off_t
pos
=
0
;
off_t
begin
=
0
;
cli
(
);
spin_lock_bh
(
&
rose_list_lock
);
len
+=
sprintf
(
buffer
,
"dest_addr dest_call src_addr src_call dev lci neigh st vs vr va t t1 t2 t3 hb idle Snd-Q Rcv-Q inode
\n
"
);
...
...
@@ -1418,15 +1415,14 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length)
if
(
pos
>
offset
+
length
)
break
;
}
sti
();
spin_unlock_bh
(
&
rose_list_lock
);
*
start
=
buffer
+
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
if
(
len
>
length
)
len
=
length
;
return
(
len
)
;
return
len
;
}
static
struct
net_proto_family
rose_family_ops
=
{
...
...
@@ -1434,7 +1430,7 @@ static struct net_proto_family rose_family_ops = {
.
create
=
rose_create
,
};
static
struct
proto_ops
SOCKOPS_WRAPPED
(
rose_proto_ops
)
=
{
static
struct
proto_ops
rose_proto_ops
=
{
.
family
=
PF_ROSE
,
.
release
=
rose_release
,
...
...
@@ -1455,11 +1451,8 @@ static struct proto_ops SOCKOPS_WRAPPED(rose_proto_ops) = {
.
sendpage
=
sock_no_sendpage
,
};
#include <linux/smp_lock.h>
SOCKOPS_WRAP
(
rose_proto
,
PF_ROSE
);
static
struct
notifier_block
rose_dev_notifier
=
{
.
notifier_call
=
rose_device_event
,
.
notifier_call
=
rose_device_event
,
};
static
struct
net_device
*
dev_rose
;
...
...
@@ -1555,5 +1548,5 @@ static void __exit rose_exit(void)
kfree
(
dev_rose
);
}
module_exit
(
rose_exit
);
module_exit
(
rose_exit
);
net/rose/rose_dev.c
View file @
a4041f6f
/*
* ROSE release 003
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from nr_dev.c.
* Hans(PE1AYX) Fixed interface to IP layer.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
...
...
@@ -29,7 +21,7 @@
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/in.h>
#include <linux/if_ether.h>
/* For the statistics structure. */
#include <linux/if_ether.h>
#include <asm/system.h>
#include <asm/io.h>
...
...
net/rose/rose_in.c
View file @
a4041f6f
/*
* ROSE release 003
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*
This code REQUIRES 2.1.15 or higher/ NET3.038
*
Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from nr_in.c
* ROSE 002 Jonathan(G4KLX) Return cause and diagnostic codes from Clear Requests.
* ROSE 003 Jonathan(G4KLX) New timer architecture.
* Removed M bit processing.
* Most of this code is based on the SDL diagrams published in the 7th ARRL
* Computer Networking Conference papers. The diagrams have mistakes in them,
* but are mostly correct. Before you modify the code could you read the SDL
* diagrams as the code is not obvious and probably very easy to break.
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
...
...
@@ -55,7 +44,6 @@ static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int framety
rose_cb
*
rose
=
rose_sk
(
sk
);
switch
(
frametype
)
{
case
ROSE_CALL_ACCEPTED
:
rose_stop_timer
(
sk
);
rose_start_idletimer
(
sk
);
...
...
@@ -93,7 +81,6 @@ static int rose_state2_machine(struct sock *sk, struct sk_buff *skb, int framety
rose_cb
*
rose
=
rose_sk
(
sk
);
switch
(
frametype
)
{
case
ROSE_CLEAR_REQUEST
:
rose_write_internal
(
sk
,
ROSE_CLEAR_CONFIRMATION
);
rose_disconnect
(
sk
,
0
,
skb
->
data
[
3
],
skb
->
data
[
4
]);
...
...
@@ -123,7 +110,6 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
int
queued
=
0
;
switch
(
frametype
)
{
case
ROSE_RESET_REQUEST
:
rose_stop_timer
(
sk
);
rose_start_idletimer
(
sk
);
...
...
@@ -232,7 +218,6 @@ static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int framety
rose_cb
*
rose
=
rose_sk
(
sk
);
switch
(
frametype
)
{
case
ROSE_RESET_REQUEST
:
rose_write_internal
(
sk
,
ROSE_RESET_CONFIRMATION
);
case
ROSE_RESET_CONFIRMATION
:
...
...
net/rose/rose_link.c
View file @
a4041f6f
/*
* ROSE release 003
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from rose_timer.c
* ROSE 003 Jonathan(G4KLX) New timer architecture.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
...
...
net/rose/rose_loopback.c
View file @
a4041f6f
/*
* ROSE release 003
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* ROSE 003 Jonathan(G4KLX) Created this file from nr_loopback.c.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/timer.h>
...
...
net/rose/rose_out.c
View file @
a4041f6f
/*
* ROSE release 003
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from nr_out.c
* ROSE 003 Jonathan(G4KLX) New timer architecture.
* Removed M bit processing.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
...
...
net/rose/rose_route.c
View file @
a4041f6f
/*
* ROSE release 003
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from nr_route.c.
* Terry(VK2KTJ) Added support for variable length
* address masks.
* ROSE 002 Jonathan(G4KLX) Uprated through routing of packets.
* Routing loop detection.
* ROSE 003 Jonathan(G4KLX) New timer architecture.
* Added use count to neighbours.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Terry Dawson VK2KTJ (terry@animats.net)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
...
...
@@ -51,8 +39,11 @@
static
unsigned
int
rose_neigh_no
=
1
;
static
struct
rose_node
*
rose_node_list
;
static
spinlock_t
rose_node_list_lock
=
SPIN_LOCK_UNLOCKED
;
static
struct
rose_neigh
*
rose_neigh_list
;
static
spinlock_t
rose_neigh_list_lock
=
SPIN_LOCK_UNLOCKED
;
static
struct
rose_route
*
rose_route_list
;
static
spinlock_t
rose_route_list_lock
=
SPIN_LOCK_UNLOCKED
;
struct
rose_neigh
*
rose_loopback_neigh
;
...
...
@@ -62,27 +53,44 @@ static void rose_remove_neigh(struct rose_neigh *);
* Add a new route to a node, and in the process add the node and the
* neighbour if it is new.
*/
static
int
rose_add_node
(
struct
rose_route_struct
*
rose_route
,
struct
net_device
*
dev
)
static
int
rose_add_node
(
struct
rose_route_struct
*
rose_route
,
struct
net_device
*
dev
)
{
struct
rose_node
*
rose_node
,
*
rose_tmpn
,
*
rose_tmpp
;
struct
rose_neigh
*
rose_neigh
;
unsigned
long
flags
;
int
i
;
int
i
,
res
=
0
;
spin_lock_bh
(
&
rose_node_list_lock
);
spin_lock_bh
(
&
rose_neigh_list_lock
);
for
(
rose_node
=
rose_node_list
;
rose_node
!=
NULL
;
rose_node
=
rose_node
->
next
)
if
((
rose_node
->
mask
==
rose_route
->
mask
)
&&
(
rosecmpm
(
&
rose_route
->
address
,
&
rose_node
->
address
,
rose_route
->
mask
)
==
0
))
rose_node
=
rose_node_list
;
while
(
rose_node
!=
NULL
)
{
if
((
rose_node
->
mask
==
rose_route
->
mask
)
&&
(
rosecmpm
(
&
rose_route
->
address
,
&
rose_node
->
address
,
rose_route
->
mask
)
==
0
))
break
;
rose_node
=
rose_node
->
next
;
}
if
(
rose_node
!=
NULL
&&
rose_node
->
loopback
)
return
-
EINVAL
;
if
(
rose_node
!=
NULL
&&
rose_node
->
loopback
)
{
res
=
-
EINVAL
;
goto
out
;
}
for
(
rose_neigh
=
rose_neigh_list
;
rose_neigh
!=
NULL
;
rose_neigh
=
rose_neigh
->
next
)
if
(
ax25cmp
(
&
rose_route
->
neighbour
,
&
rose_neigh
->
callsign
)
==
0
&&
rose_neigh
->
dev
==
dev
)
rose_neigh
=
rose_neigh_list
;
while
(
rose_neigh
!=
NULL
)
{
if
(
ax25cmp
(
&
rose_route
->
neighbour
,
&
rose_neigh
->
callsign
)
==
0
&&
rose_neigh
->
dev
==
dev
)
break
;
rose_neigh
=
rose_neigh
->
next
;
}
if
(
rose_neigh
==
NULL
)
{
if
((
rose_neigh
=
kmalloc
(
sizeof
(
*
rose_neigh
),
GFP_ATOMIC
))
==
NULL
)
return
-
ENOMEM
;
rose_neigh
=
kmalloc
(
sizeof
(
*
rose_neigh
),
GFP_ATOMIC
);
if
(
rose_neigh
==
NULL
)
{
res
=
-
ENOMEM
;
goto
out
;
}
rose_neigh
->
callsign
=
rose_route
->
neighbour
;
rose_neigh
->
digipeat
=
NULL
;
...
...
@@ -103,22 +111,22 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
if
(
rose_route
->
ndigis
!=
0
)
{
if
((
rose_neigh
->
digipeat
=
kmalloc
(
sizeof
(
ax25_digi
),
GFP_KERNEL
))
==
NULL
)
{
kfree
(
rose_neigh
);
return
-
ENOMEM
;
res
=
-
ENOMEM
;
goto
out
;
}
rose_neigh
->
digipeat
->
ndigi
=
rose_route
->
ndigis
;
rose_neigh
->
digipeat
->
lastrepeat
=
-
1
;
for
(
i
=
0
;
i
<
rose_route
->
ndigis
;
i
++
)
{
rose_neigh
->
digipeat
->
calls
[
i
]
=
rose_route
->
digipeaters
[
i
];
rose_neigh
->
digipeat
->
calls
[
i
]
=
rose_route
->
digipeaters
[
i
];
rose_neigh
->
digipeat
->
repeated
[
i
]
=
0
;
}
}
save_flags
(
flags
);
cli
();
rose_neigh
->
next
=
rose_neigh_list
;
rose_neigh_list
=
rose_neigh
;
restore_flags
(
flags
);
}
/*
...
...
@@ -142,8 +150,11 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
}
/* create new node */
if
((
rose_node
=
kmalloc
(
sizeof
(
*
rose_node
),
GFP_ATOMIC
))
==
NULL
)
return
-
ENOMEM
;
rose_node
=
kmalloc
(
sizeof
(
*
rose_node
),
GFP_ATOMIC
);
if
(
rose_node
==
NULL
)
{
res
=
-
ENOMEM
;
goto
out
;
}
rose_node
->
address
=
rose_route
->
address
;
rose_node
->
mask
=
rose_route
->
mask
;
...
...
@@ -151,8 +162,6 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
rose_node
->
loopback
=
0
;
rose_node
->
neighbour
[
0
]
=
rose_neigh
;
save_flags
(
flags
);
cli
();
if
(
rose_tmpn
==
NULL
)
{
if
(
rose_tmpp
==
NULL
)
{
/* Empty list */
rose_node_list
=
rose_node
;
...
...
@@ -170,12 +179,9 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
rose_node
->
next
=
rose_tmpn
;
}
}
restore_flags
(
flags
);
rose_neigh
->
count
++
;
return
0
;
goto
out
;
}
/* We have space, slot it in */
...
...
@@ -185,20 +191,23 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
rose_neigh
->
count
++
;
}
return
0
;
out:
spin_unlock_bh
(
&
rose_neigh_list_lock
);
spin_unlock_bh
(
&
rose_node_list_lock
);
return
res
;
}
/*
* Caller is holding rose_node_list_lock.
*/
static
void
rose_remove_node
(
struct
rose_node
*
rose_node
)
{
struct
rose_node
*
s
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
rose_node_list_lock
);
if
((
s
=
rose_node_list
)
==
rose_node
)
{
rose_node_list
=
rose_node
->
next
;
restore_flags
(
flags
);
kfree
(
rose_node
);
return
;
}
...
...
@@ -206,32 +215,31 @@ static void rose_remove_node(struct rose_node *rose_node)
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
if
(
s
->
next
==
rose_node
)
{
s
->
next
=
rose_node
->
next
;
restore_flags
(
flags
);
kfree
(
rose_node
);
return
;
}
s
=
s
->
next
;
}
restore_flags
(
flags
);
}
/*
* Caller is holding rose_neigh_list_lock.
*/
static
void
rose_remove_neigh
(
struct
rose_neigh
*
rose_neigh
)
{
struct
rose_neigh
*
s
;
unsigned
long
flags
;
rose_stop_ftimer
(
rose_neigh
);
rose_stop_t0timer
(
rose_neigh
);
skb_queue_purge
(
&
rose_neigh
->
queue
);
s
ave_flags
(
flags
);
cli
(
);
s
pin_lock_bh
(
&
rose_neigh_list_lock
);
if
((
s
=
rose_neigh_list
)
==
rose_neigh
)
{
rose_neigh_list
=
rose_neigh
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
rose_neigh_list_lock
);
if
(
rose_neigh
->
digipeat
!=
NULL
)
kfree
(
rose_neigh
->
digipeat
);
kfree
(
rose_neigh
);
...
...
@@ -241,7 +249,7 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
if
(
s
->
next
==
rose_neigh
)
{
s
->
next
=
rose_neigh
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
rose_neigh_list_lock
);
if
(
rose_neigh
->
digipeat
!=
NULL
)
kfree
(
rose_neigh
->
digipeat
);
kfree
(
rose_neigh
);
...
...
@@ -250,14 +258,15 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
s
=
s
->
next
;
}
restore_flags
(
flags
);
spin_unlock_bh
(
&
rose_neigh_list_lock
);
}
/*
* Caller is holding rose_route_list_lock.
*/
static
void
rose_remove_route
(
struct
rose_route
*
rose_route
)
{
struct
rose_route
*
s
;
unsigned
long
flags
;
if
(
rose_route
->
neigh1
!=
NULL
)
rose_route
->
neigh1
->
use
--
;
...
...
@@ -265,11 +274,8 @@ static void rose_remove_route(struct rose_route *rose_route)
if
(
rose_route
->
neigh2
!=
NULL
)
rose_route
->
neigh2
->
use
--
;
save_flags
(
flags
);
cli
();
if
((
s
=
rose_route_list
)
==
rose_route
)
{
rose_route_list
=
rose_route
->
next
;
restore_flags
(
flags
);
kfree
(
rose_route
);
return
;
}
...
...
@@ -277,40 +283,54 @@ static void rose_remove_route(struct rose_route *rose_route)
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
if
(
s
->
next
==
rose_route
)
{
s
->
next
=
rose_route
->
next
;
restore_flags
(
flags
);
kfree
(
rose_route
);
return
;
}
s
=
s
->
next
;
}
restore_flags
(
flags
);
}
/*
* "Delete" a node. Strictly speaking remove a route to a node. The node
* is only deleted if no routes are left to it.
*/
static
int
rose_del_node
(
struct
rose_route_struct
*
rose_route
,
struct
net_device
*
dev
)
static
int
rose_del_node
(
struct
rose_route_struct
*
rose_route
,
struct
net_device
*
dev
)
{
struct
rose_node
*
rose_node
;
struct
rose_neigh
*
rose_neigh
;
int
i
;
int
i
,
err
=
0
;
for
(
rose_node
=
rose_node_list
;
rose_node
!=
NULL
;
rose_node
=
rose_node
->
next
)
if
((
rose_node
->
mask
==
rose_route
->
mask
)
&&
(
rosecmpm
(
&
rose_route
->
address
,
&
rose_node
->
address
,
rose_route
->
mask
)
==
0
))
break
;
spin_lock_bh
(
&
rose_node_list_lock
);
spin_lock_bh
(
&
rose_neigh_list_lock
);
if
(
rose_node
==
NULL
)
return
-
EINVAL
;
rose_node
=
rose_node_list
;
while
(
rose_node
!=
NULL
)
{
if
((
rose_node
->
mask
==
rose_route
->
mask
)
&&
(
rosecmpm
(
&
rose_route
->
address
,
&
rose_node
->
address
,
rose_route
->
mask
)
==
0
))
break
;
rose_node
=
rose_node
->
next
;
}
if
(
rose_node
->
loopback
)
return
-
EINVAL
;
if
(
rose_node
==
NULL
||
rose_node
->
loopback
)
{
err
=
-
EINVAL
;
goto
out
;
}
for
(
rose_neigh
=
rose_neigh_list
;
rose_neigh
!=
NULL
;
rose_neigh
=
rose_neigh
->
next
)
if
(
ax25cmp
(
&
rose_route
->
neighbour
,
&
rose_neigh
->
callsign
)
==
0
&&
rose_neigh
->
dev
==
dev
)
rose_neigh
=
rose_neigh_list
;
while
(
rose_neigh
!=
NULL
)
{
if
(
ax25cmp
(
&
rose_route
->
neighbour
,
&
rose_neigh
->
callsign
)
==
0
&&
rose_neigh
->
dev
==
dev
)
break
;
rose_neigh
=
rose_neigh
->
next
;
}
if
(
rose_neigh
==
NULL
)
return
-
EINVAL
;
if
(
rose_neigh
==
NULL
)
{
err
=
-
EINVAL
;
goto
out
;
}
for
(
i
=
0
;
i
<
rose_node
->
count
;
i
++
)
{
if
(
rose_node
->
neighbour
[
i
]
==
rose_neigh
)
{
...
...
@@ -326,19 +346,25 @@ static int rose_del_node(struct rose_route_struct *rose_route, struct net_device
}
else
{
switch
(
i
)
{
case
0
:
rose_node
->
neighbour
[
0
]
=
rose_node
->
neighbour
[
1
];
rose_node
->
neighbour
[
0
]
=
rose_node
->
neighbour
[
1
];
case
1
:
rose_node
->
neighbour
[
1
]
=
rose_node
->
neighbour
[
2
];
rose_node
->
neighbour
[
1
]
=
rose_node
->
neighbour
[
2
];
case
2
:
break
;
}
}
return
0
;
goto
out
;
}
}
err
=
-
EINVAL
;
return
-
EINVAL
;
out:
spin_unlock_bh
(
&
rose_neigh_list_lock
);
spin_unlock_bh
(
&
rose_node_list_lock
);
return
err
;
}
/*
...
...
@@ -346,8 +372,6 @@ static int rose_del_node(struct rose_route_struct *rose_route, struct net_device
*/
int
rose_add_loopback_neigh
(
void
)
{
unsigned
long
flags
;
if
((
rose_loopback_neigh
=
kmalloc
(
sizeof
(
struct
rose_neigh
),
GFP_ATOMIC
))
==
NULL
)
return
-
ENOMEM
;
...
...
@@ -367,10 +391,10 @@ int rose_add_loopback_neigh(void)
init_timer
(
&
rose_loopback_neigh
->
ftimer
);
init_timer
(
&
rose_loopback_neigh
->
t0timer
);
s
ave_flags
(
flags
);
cli
(
);
s
pin_lock_bh
(
&
rose_neigh_list_lock
);
rose_loopback_neigh
->
next
=
rose_neigh_list
;
rose_neigh_list
=
rose_loopback_neigh
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
rose_neigh_list_lock
);
return
0
;
}
...
...
@@ -381,16 +405,26 @@ int rose_add_loopback_neigh(void)
int
rose_add_loopback_node
(
rose_address
*
address
)
{
struct
rose_node
*
rose_node
;
unsigned
long
flags
;
unsigned
int
err
=
0
;
for
(
rose_node
=
rose_node_list
;
rose_node
!=
NULL
;
rose_node
=
rose_node
->
next
)
if
((
rose_node
->
mask
==
10
)
&&
(
rosecmpm
(
address
,
&
rose_node
->
address
,
10
)
==
0
)
&&
rose_node
->
loopback
)
spin_lock_bh
(
&
rose_node_list_lock
);
rose_node
=
rose_node_list
;
while
(
rose_node
!=
NULL
)
{
if
((
rose_node
->
mask
==
10
)
&&
(
rosecmpm
(
address
,
&
rose_node
->
address
,
10
)
==
0
)
&&
rose_node
->
loopback
)
break
;
rose_node
=
rose_node
->
next
;
}
if
(
rose_node
!=
NULL
)
return
0
;
if
(
rose_node
!=
NULL
)
goto
out
;
if
((
rose_node
=
kmalloc
(
sizeof
(
*
rose_node
),
GFP_ATOMIC
))
==
NULL
)
return
-
ENOMEM
;
if
((
rose_node
=
kmalloc
(
sizeof
(
*
rose_node
),
GFP_ATOMIC
))
==
NULL
)
{
err
=
-
ENOMEM
;
goto
out
;
}
rose_node
->
address
=
*
address
;
rose_node
->
mask
=
10
;
...
...
@@ -399,13 +433,14 @@ int rose_add_loopback_node(rose_address *address)
rose_node
->
neighbour
[
0
]
=
rose_loopback_neigh
;
/* Insert at the head of list. Address is always mask=10 */
save_flags
(
flags
);
cli
();
rose_node
->
next
=
rose_node_list
;
rose_node_list
=
rose_node
;
restore_flags
(
flags
);
rose_loopback_neigh
->
count
++
;
out:
spin_unlock_bh
(
&
rose_node_list_lock
);
return
0
;
}
...
...
@@ -416,15 +451,26 @@ void rose_del_loopback_node(rose_address *address)
{
struct
rose_node
*
rose_node
;
for
(
rose_node
=
rose_node_list
;
rose_node
!=
NULL
;
rose_node
=
rose_node
->
next
)
if
((
rose_node
->
mask
==
10
)
&&
(
rosecmpm
(
address
,
&
rose_node
->
address
,
10
)
==
0
)
&&
rose_node
->
loopback
)
spin_lock_bh
(
&
rose_node_list_lock
);
rose_node
=
rose_node_list
;
while
(
rose_node
!=
NULL
)
{
if
((
rose_node
->
mask
==
10
)
&&
(
rosecmpm
(
address
,
&
rose_node
->
address
,
10
)
==
0
)
&&
rose_node
->
loopback
)
break
;
rose_node
=
rose_node
->
next
;
}
if
(
rose_node
==
NULL
)
return
;
if
(
rose_node
==
NULL
)
goto
out
;
rose_remove_node
(
rose_node
);
rose_loopback_neigh
->
count
--
;
out:
spin_unlock_bh
(
&
rose_node_list_lock
);
}
/*
...
...
@@ -432,15 +478,20 @@ void rose_del_loopback_node(rose_address *address)
*/
void
rose_rt_device_down
(
struct
net_device
*
dev
)
{
struct
rose_neigh
*
s
,
*
rose_neigh
=
rose_neigh_list
;
struct
rose_neigh
*
s
,
*
rose_neigh
;
struct
rose_node
*
t
,
*
rose_node
;
int
i
;
spin_lock_bh
(
&
rose_node_list_lock
);
spin_lock_bh
(
&
rose_neigh_list_lock
);
rose_neigh
=
rose_neigh_list
;
while
(
rose_neigh
!=
NULL
)
{
s
=
rose_neigh
;
rose_neigh
=
rose_neigh
->
next
;
if
(
s
->
dev
==
dev
)
{
if
(
s
->
dev
!=
dev
)
continue
;
rose_node
=
rose_node_list
;
while
(
rose_node
!=
NULL
)
{
...
...
@@ -448,7 +499,9 @@ void rose_rt_device_down(struct net_device *dev)
rose_node
=
rose_node
->
next
;
for
(
i
=
0
;
i
<
t
->
count
;
i
++
)
{
if
(
t
->
neighbour
[
i
]
==
s
)
{
if
(
t
->
neighbour
[
i
]
!=
s
)
continue
;
t
->
count
--
;
switch
(
i
)
{
...
...
@@ -460,7 +513,6 @@ void rose_rt_device_down(struct net_device *dev)
break
;
}
}
}
if
(
t
->
count
<=
0
)
rose_remove_node
(
t
);
...
...
@@ -468,16 +520,20 @@ void rose_rt_device_down(struct net_device *dev)
rose_remove_neigh
(
s
);
}
}
spin_unlock_bh
(
&
rose_neigh_list_lock
);
spin_unlock_bh
(
&
rose_node_list_lock
);
}
#if 0 /* Currently unused */
/*
* A device has been removed. Remove its links.
*/
void rose_route_device_down(struct net_device *dev)
{
struct
rose_route
*
s
,
*
rose_route
=
rose_route_list
;
struct rose_route *s, *rose_route;
spin_lock_bh(&rose_route_list_lock);
rose_route = rose_route_list;
while (rose_route != NULL) {
s = rose_route;
rose_route = rose_route->next;
...
...
@@ -485,7 +541,9 @@ void rose_route_device_down(struct net_device *dev)
if (s->neigh1->dev == dev || s->neigh2->dev == dev)
rose_remove_route(s);
}
spin_unlock_bh(&rose_route_list_lock);
}
#endif
/*
* Clear all nodes and neighbours out, except for neighbours with
...
...
@@ -494,8 +552,14 @@ void rose_route_device_down(struct net_device *dev)
*/
static
int
rose_clear_routes
(
void
)
{
struct
rose_neigh
*
s
,
*
rose_neigh
=
rose_neigh_list
;
struct
rose_node
*
t
,
*
rose_node
=
rose_node_list
;
struct
rose_neigh
*
s
,
*
rose_neigh
;
struct
rose_node
*
t
,
*
rose_node
;
spin_lock_bh
(
&
rose_node_list_lock
);
spin_lock_bh
(
&
rose_neigh_list_lock
);
rose_neigh
=
rose_neigh_list
;
rose_node
=
rose_node_list
;
while
(
rose_node
!=
NULL
)
{
t
=
rose_node
;
...
...
@@ -514,6 +578,9 @@ static int rose_clear_routes(void)
}
}
spin_unlock_bh
(
&
rose_neigh_list_lock
);
spin_unlock_bh
(
&
rose_node_list_lock
);
return
0
;
}
...
...
@@ -603,18 +670,22 @@ struct rose_route *rose_route_free_lci(unsigned int lci, struct rose_neigh *neig
/*
* Find a neighbour given a ROSE address.
*/
struct
rose_neigh
*
rose_get_neigh
(
rose_address
*
addr
,
unsigned
char
*
cause
,
unsigned
char
*
diagnostic
)
struct
rose_neigh
*
rose_get_neigh
(
rose_address
*
addr
,
unsigned
char
*
cause
,
unsigned
char
*
diagnostic
)
{
struct
rose_neigh
*
res
=
NULL
;
struct
rose_node
*
node
;
int
failed
=
0
;
int
i
;
spin_lock_bh
(
&
rose_node_list_lock
);
for
(
node
=
rose_node_list
;
node
!=
NULL
;
node
=
node
->
next
)
{
if
(
rosecmpm
(
addr
,
&
node
->
address
,
node
->
mask
)
==
0
)
{
for
(
i
=
0
;
i
<
node
->
count
;
i
++
)
{
if
(
!
rose_ftimer_running
(
node
->
neighbour
[
i
]))
{
return
node
->
neighbour
[
i
];
}
else
res
=
node
->
neighbour
[
i
];
goto
out
;
}
else
failed
=
1
;
}
break
;
...
...
@@ -629,7 +700,10 @@ struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, unsi
*
diagnostic
=
0
;
}
return
NULL
;
out:
spin_unlock_bh
(
&
rose_node_list_lock
);
return
res
;
}
/*
...
...
@@ -642,7 +716,6 @@ int rose_rt_ioctl(unsigned int cmd, void *arg)
int
err
;
switch
(
cmd
)
{
case
SIOCADDRT
:
if
(
copy_from_user
(
&
rose_route
,
arg
,
sizeof
(
struct
rose_route_struct
)))
return
-
EFAULT
;
...
...
@@ -668,7 +741,6 @@ int rose_rt_ioctl(unsigned int cmd, void *arg)
dev_put
(
dev
);
return
err
;
case
SIOCRSCLRRT
:
return
rose_clear_routes
();
...
...
@@ -690,6 +762,8 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
skb_queue_purge
(
&
rose_neigh
->
queue
);
spin_lock_bh
(
&
rose_route_list_lock
);
rose_route
=
rose_route_list
;
while
(
rose_route
!=
NULL
)
{
...
...
@@ -716,6 +790,7 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
rose_route
=
rose_route
->
next
;
}
spin_unlock_bh
(
&
rose_route_list_lock
);
}
/*
...
...
@@ -727,16 +802,21 @@ void rose_link_failed(ax25_cb *ax25, int reason)
{
struct
rose_neigh
*
rose_neigh
;
for
(
rose_neigh
=
rose_neigh_list
;
rose_neigh
!=
NULL
;
rose_neigh
=
rose_neigh
->
next
)
spin_lock_bh
(
&
rose_neigh_list_lock
);
rose_neigh
=
rose_neigh_list
;
while
(
rose_neigh
!=
NULL
)
{
if
(
rose_neigh
->
ax25
==
ax25
)
break
;
rose_neigh
=
rose_neigh
->
next
;
}
if
(
rose_neigh
==
NULL
)
return
;
if
(
rose_neigh
!=
NULL
)
{
rose_neigh
->
ax25
=
NULL
;
rose_del_route_by_neigh
(
rose_neigh
);
rose_kill_by_neigh
(
rose_neigh
);
}
spin_unlock_bh
(
&
rose_neigh_list_lock
);
}
/*
...
...
@@ -769,12 +849,11 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
unsigned
int
lci
,
new_lci
;
unsigned
char
cause
,
diagnostic
;
struct
net_device
*
dev
;
unsigned
long
flags
;
int
len
;
int
len
,
res
=
0
;
#if 0
if (call_in_firewall(PF_ROSE, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT)
return
0
;
return
res
;
#endif
frametype
=
skb
->
data
[
2
];
...
...
@@ -782,13 +861,22 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
src_addr
=
(
rose_address
*
)(
skb
->
data
+
9
);
dest_addr
=
(
rose_address
*
)(
skb
->
data
+
4
);
for
(
rose_neigh
=
rose_neigh_list
;
rose_neigh
!=
NULL
;
rose_neigh
=
rose_neigh
->
next
)
if
(
ax25cmp
(
&
ax25
->
dest_addr
,
&
rose_neigh
->
callsign
)
==
0
&&
ax25
->
ax25_dev
->
dev
==
rose_neigh
->
dev
)
spin_lock_bh
(
&
rose_node_list_lock
);
spin_lock_bh
(
&
rose_neigh_list_lock
);
spin_lock_bh
(
&
rose_route_list_lock
);
rose_neigh
=
rose_neigh_list
;
while
(
rose_neigh
!=
NULL
)
{
if
(
ax25cmp
(
&
ax25
->
dest_addr
,
&
rose_neigh
->
callsign
)
==
0
&&
ax25
->
ax25_dev
->
dev
==
rose_neigh
->
dev
)
break
;
rose_neigh
=
rose_neigh
->
next
;
}
if
(
rose_neigh
==
NULL
)
{
printk
(
"rose_route : unknown neighbour or device %s
\n
"
,
ax2asc
(
&
ax25
->
dest_addr
));
return
0
;
printk
(
"rose_route : unknown neighbour or device %s
\n
"
,
ax2asc
(
&
ax25
->
dest_addr
));
goto
out
;
}
/*
...
...
@@ -802,7 +890,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
*/
if
(
lci
==
0
)
{
rose_link_rx_restart
(
skb
,
rose_neigh
,
frametype
);
return
0
;
goto
out
;
}
/*
...
...
@@ -828,7 +916,8 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
}
else
{
skb
->
h
.
raw
=
skb
->
data
;
return
rose_process_rx_frame
(
sk
,
skb
);
res
=
rose_process_rx_frame
(
sk
,
skb
);
goto
out
;
}
}
...
...
@@ -837,21 +926,23 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
*/
if
(
frametype
==
ROSE_CALL_REQUEST
)
if
((
dev
=
rose_dev_get
(
dest_addr
))
!=
NULL
)
{
int
err
=
rose_rx_call_request
(
skb
,
dev
,
rose_neigh
,
lci
);
res
=
rose_rx_call_request
(
skb
,
dev
,
rose_neigh
,
lci
);
dev_put
(
dev
);
return
err
;
goto
out
;
}
if
(
!
sysctl_rose_routing_control
)
{
rose_transmit_clear_request
(
rose_neigh
,
lci
,
ROSE_NOT_OBTAINABLE
,
0
);
return
0
;
goto
out
;
}
/*
* Route it to the next in line if we have an entry for it.
*/
for
(
rose_route
=
rose_route_list
;
rose_route
!=
NULL
;
rose_route
=
rose_route
->
next
)
{
if
(
rose_route
->
lci1
==
lci
&&
rose_route
->
neigh1
==
rose_neigh
)
{
rose_route
=
rose_route_list
;
while
(
rose_route
!=
NULL
)
{
if
(
rose_route
->
lci1
==
lci
&&
rose_route
->
neigh1
==
rose_neigh
)
{
if
(
frametype
==
ROSE_CALL_REQUEST
)
{
/* F6FBB - Remove an existing unused route */
rose_remove_route
(
rose_route
);
...
...
@@ -863,14 +954,16 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
rose_transmit_link
(
skb
,
rose_route
->
neigh2
);
if
(
frametype
==
ROSE_CLEAR_CONFIRMATION
)
rose_remove_route
(
rose_route
);
return
1
;
res
=
1
;
goto
out
;
}
else
{
if
(
frametype
==
ROSE_CLEAR_CONFIRMATION
)
rose_remove_route
(
rose_route
);
return
0
;
goto
out
;
}
}
if
(
rose_route
->
lci2
==
lci
&&
rose_route
->
neigh2
==
rose_neigh
)
{
if
(
rose_route
->
lci2
==
lci
&&
rose_route
->
neigh2
==
rose_neigh
)
{
if
(
frametype
==
ROSE_CALL_REQUEST
)
{
/* F6FBB - Remove an existing unused route */
rose_remove_route
(
rose_route
);
...
...
@@ -882,13 +975,15 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
rose_transmit_link
(
skb
,
rose_route
->
neigh1
);
if
(
frametype
==
ROSE_CLEAR_CONFIRMATION
)
rose_remove_route
(
rose_route
);
return
1
;
res
=
1
;
goto
out
;
}
else
{
if
(
frametype
==
ROSE_CLEAR_CONFIRMATION
)
rose_remove_route
(
rose_route
);
return
0
;
goto
out
;
}
}
rose_route
=
rose_route
->
next
;
}
/*
...
...
@@ -906,35 +1001,37 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
if
(
!
rose_parse_facilities
(
skb
->
data
+
len
+
4
,
&
facilities
))
{
rose_transmit_clear_request
(
rose_neigh
,
lci
,
ROSE_INVALID_FACILITY
,
76
);
return
0
;
goto
out
;
}
/*
* Check for routing loops.
*/
for
(
rose_route
=
rose_route_list
;
rose_route
!=
NULL
;
rose_route
=
rose_route
->
next
)
{
rose_route
=
rose_route_list
;
while
(
rose_route
!=
NULL
)
{
if
(
rose_route
->
rand
==
facilities
.
rand
&&
rosecmp
(
src_addr
,
&
rose_route
->
src_addr
)
==
0
&&
ax25cmp
(
&
facilities
.
dest_call
,
&
rose_route
->
src_call
)
==
0
&&
ax25cmp
(
&
facilities
.
source_call
,
&
rose_route
->
dest_call
)
==
0
)
{
rose_transmit_clear_request
(
rose_neigh
,
lci
,
ROSE_NOT_OBTAINABLE
,
120
);
return
0
;
goto
out
;
}
rose_route
=
rose_route
->
next
;
}
if
((
new_neigh
=
rose_get_neigh
(
dest_addr
,
&
cause
,
&
diagnostic
))
==
NULL
)
{
rose_transmit_clear_request
(
rose_neigh
,
lci
,
cause
,
diagnostic
);
return
0
;
goto
out
;
}
if
((
new_lci
=
rose_new_lci
(
new_neigh
))
==
0
)
{
rose_transmit_clear_request
(
rose_neigh
,
lci
,
ROSE_NETWORK_CONGESTION
,
71
);
return
0
;
goto
out
;
}
if
((
rose_route
=
kmalloc
(
sizeof
(
*
rose_route
),
GFP_ATOMIC
))
==
NULL
)
{
rose_transmit_clear_request
(
rose_neigh
,
lci
,
ROSE_NETWORK_CONGESTION
,
120
);
return
0
;
goto
out
;
}
rose_route
->
lci1
=
lci
;
...
...
@@ -950,18 +1047,22 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
rose_route
->
neigh1
->
use
++
;
rose_route
->
neigh2
->
use
++
;
save_flags
(
flags
);
cli
();
rose_route
->
next
=
rose_route_list
;
rose_route_list
=
rose_route
;
restore_flags
(
flags
);
skb
->
data
[
0
]
&=
0xF0
;
skb
->
data
[
0
]
|=
(
rose_route
->
lci2
>>
8
)
&
0x0F
;
skb
->
data
[
1
]
=
(
rose_route
->
lci2
>>
0
)
&
0xFF
;
rose_transmit_link
(
skb
,
rose_route
->
neigh2
);
res
=
1
;
out:
spin_unlock_bh
(
&
rose_route_list_lock
);
spin_unlock_bh
(
&
rose_neigh_list_lock
);
spin_unlock_bh
(
&
rose_node_list_lock
);
return
1
;
return
res
;
}
int
rose_nodes_get_info
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
...
...
@@ -972,7 +1073,7 @@ int rose_nodes_get_info(char *buffer, char **start, off_t offset, int length)
off_t
begin
=
0
;
int
i
;
cli
(
);
spin_lock_bh
(
&
rose_neigh_list_lock
);
len
+=
sprintf
(
buffer
,
"address mask n neigh neigh neigh
\n
"
);
...
...
@@ -1004,13 +1105,13 @@ int rose_nodes_get_info(char *buffer, char **start, off_t offset, int length)
if
(
pos
>
offset
+
length
)
break
;
}
sti
();
spin_unlock_bh
(
&
rose_neigh_list_lock
);
*
start
=
buffer
+
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
if
(
len
>
length
)
len
=
length
;
if
(
len
>
length
)
len
=
length
;
return
len
;
}
...
...
@@ -1023,7 +1124,7 @@ int rose_neigh_get_info(char *buffer, char **start, off_t offset, int length)
off_t
begin
=
0
;
int
i
;
cli
(
);
spin_lock_bh
(
&
rose_neigh_list_lock
);
len
+=
sprintf
(
buffer
,
"addr callsign dev count use mode restart t0 tf digipeaters
\n
"
);
...
...
@@ -1059,12 +1160,13 @@ int rose_neigh_get_info(char *buffer, char **start, off_t offset, int length)
/* } */
}
s
ti
(
);
s
pin_unlock_bh
(
&
rose_neigh_list_lock
);
*
start
=
buffer
+
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
if
(
len
>
length
)
len
=
length
;
if
(
len
>
length
)
len
=
length
;
return
len
;
}
...
...
@@ -1076,7 +1178,7 @@ int rose_routes_get_info(char *buffer, char **start, off_t offset, int length)
off_t
pos
=
0
;
off_t
begin
=
0
;
cli
(
);
spin_lock_bh
(
&
rose_route_list_lock
);
len
+=
sprintf
(
buffer
,
"lci address callsign neigh <-> lci address callsign neigh
\n
"
);
...
...
@@ -1112,12 +1214,13 @@ int rose_routes_get_info(char *buffer, char **start, off_t offset, int length)
break
;
}
s
ti
(
);
s
pin_unlock_bh
(
&
rose_route_list_lock
);
*
start
=
buffer
+
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
if
(
len
>
length
)
len
=
length
;
if
(
len
>
length
)
len
=
length
;
return
len
;
}
...
...
net/rose/rose_subr.c
View file @
a4041f6f
/*
* ROSE release 003
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from nr_subr.c
* ROSE 002 Jonathan(G4KLX) Centralised disconnect processing.
* ROSE 003 Jonathan(G4KLX) Added use count to neighbours.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
...
...
@@ -145,7 +136,6 @@ void rose_write_internal(struct sock *sk, int frametype)
lci2
=
(
rose
->
lci
>>
0
)
&
0xFF
;
switch
(
frametype
)
{
case
ROSE_CALL_REQUEST
:
*
dptr
++
=
ROSE_GFI
|
lci1
;
*
dptr
++
=
lci2
;
...
...
@@ -363,7 +353,8 @@ static int rose_parse_ccitt(unsigned char *p, struct rose_facilities_struct *fac
return
n
;
}
int
rose_parse_facilities
(
unsigned
char
*
p
,
struct
rose_facilities_struct
*
facilities
)
int
rose_parse_facilities
(
unsigned
char
*
p
,
struct
rose_facilities_struct
*
facilities
)
{
int
facilities_len
,
len
;
...
...
@@ -396,8 +387,8 @@ int rose_parse_facilities(unsigned char *p, struct rose_facilities_struct *facil
p
++
;
break
;
}
}
else
break
;
/* Error in facilities format */
}
else
break
;
/* Error in facilities format */
}
return
1
;
...
...
net/rose/rose_timer.c
View file @
a4041f6f
/*
* ROSE release 003
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from nr_timer.c
* ROSE 003 Jonathan(G4KLX) New timer architecture.
* Implemented idle timer.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
...
...
@@ -139,8 +131,8 @@ static void rose_heartbeat_expiry(unsigned long param)
struct
sock
*
sk
=
(
struct
sock
*
)
param
;
rose_cb
*
rose
=
rose_sk
(
sk
);
bh_lock_sock
(
sk
);
switch
(
rose
->
state
)
{
case
ROSE_STATE_0
:
/* Magic here: If we listen() and a new link dies before it
is accepted() it isn't 'dead' so doesn't get removed. */
...
...
@@ -167,6 +159,7 @@ static void rose_heartbeat_expiry(unsigned long param)
}
rose_start_heartbeat
(
sk
);
bh_unlock_sock
(
sk
);
}
static
void
rose_timer_expiry
(
unsigned
long
param
)
...
...
@@ -174,8 +167,8 @@ static void rose_timer_expiry(unsigned long param)
struct
sock
*
sk
=
(
struct
sock
*
)
param
;
rose_cb
*
rose
=
rose_sk
(
sk
);
bh_lock_sock
(
sk
);
switch
(
rose
->
state
)
{
case
ROSE_STATE_1
:
/* T1 */
case
ROSE_STATE_4
:
/* T2 */
rose_write_internal
(
sk
,
ROSE_CLEAR_REQUEST
);
...
...
@@ -195,12 +188,14 @@ static void rose_timer_expiry(unsigned long param)
}
break
;
}
bh_unlock_sock
(
sk
);
}
static
void
rose_idletimer_expiry
(
unsigned
long
param
)
{
struct
sock
*
sk
=
(
struct
sock
*
)
param
;
bh_lock_sock
(
sk
);
rose_clear_queues
(
sk
);
rose_write_internal
(
sk
,
ROSE_CLEAR_REQUEST
);
...
...
@@ -216,4 +211,5 @@ static void rose_idletimer_expiry(unsigned long param)
sk
->
state_change
(
sk
);
sk
->
dead
=
1
;
bh_unlock_sock
(
sk
);
}
net/rose/sysctl_net_rose.c
View file @
a4041f6f
/* -*- linux-c -*-
* sysctl_net_rose.c: sysctl interface to net ROSE subsystem.
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Begun April 1, 1996, Mike Shaver.
* Added /proc/sys/net/rose directory entry (empty =) ). [MS]
* Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com)
*/
#include <linux/mm.h>
#include <linux/sysctl.h>
#include <linux/init.h>
...
...
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