Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
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