Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
2bb0a0bb
Commit
2bb0a0bb
authored
Mar 16, 2004
by
Ralf Bächle
Committed by
Jeff Garzik
Mar 16, 2004
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[hamradio 6pack] cleanup
parent
f2710107
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
543 additions
and
546 deletions
+543
-546
drivers/net/hamradio/6pack.c
drivers/net/hamradio/6pack.c
+543
-546
No files found.
drivers/net/hamradio/6pack.c
View file @
2bb0a0bb
...
@@ -3,15 +3,13 @@
...
@@ -3,15 +3,13 @@
* devices like TTY. It interfaces between a raw TTY and the
* devices like TTY. It interfaces between a raw TTY and the
* kernel's AX.25 protocol layers.
* kernel's AX.25 protocol layers.
*
*
* Version: @(#)6pack.c 0.3.0 04/07/98
*
* Authors: Andreas Knsgen <ajk@iehk.rwth-aachen.de>
* Authors: Andreas Knsgen <ajk@iehk.rwth-aachen.de>
* Ralf Baechle DO1GRB <ralf@linux-mips.org>
*
*
* Quite a lot of stuff "stolen" by Jrg Reuter from slip.c, written by
* Quite a lot of stuff "stolen" by J
oe
rg Reuter from slip.c, written by
*
*
* Laurence Culhane, <loz@holmes.demon.co.uk>
* Laurence Culhane, <loz@holmes.demon.co.uk>
* Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
* Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
*
*/
*/
#include <linux/config.h>
#include <linux/config.h>
...
@@ -31,20 +29,23 @@
...
@@ -31,20 +29,23 @@
#include <linux/etherdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/skbuff.h>
#include <linux/rtnetlink.h>
#include <linux/rtnetlink.h>
#include <linux/spinlock.h>
#include <linux/if_arp.h>
#include <linux/if_arp.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/ip.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/tcp.h>
#include <asm/semaphore.h>
#include <asm/atomic.h>
#define SIXPACK_VERSION "Revision: 0.3.0"
#define SIXPACK_VERSION "Revision: 0.3.0"
/* sixpack priority commands */
/* sixpack priority commands */
#define SIXP_SEOF 0x40
/* start and end of a 6pack frame */
#define SIXP_SEOF
0x40
/* start and end of a 6pack frame */
#define SIXP_TX_URUN 0x48
/* transmit overrun */
#define SIXP_TX_URUN
0x48
/* transmit overrun */
#define SIXP_RX_ORUN 0x50
/* receive overrun */
#define SIXP_RX_ORUN
0x50
/* receive overrun */
#define SIXP_RX_BUF_OVL 0x58
/* receive buffer overflow */
#define SIXP_RX_BUF_OVL
0x58
/* receive buffer overflow */
#define SIXP_CHKSUM 0xFF
/* valid checksum of a 6pack frame */
#define SIXP_CHKSUM
0xFF
/* valid checksum of a 6pack frame */
/* masks to get certain bits out of the status bytes sent by the TNC */
/* masks to get certain bits out of the status bytes sent by the TNC */
...
@@ -78,23 +79,20 @@
...
@@ -78,23 +79,20 @@
#define SIXP_MTU 256
/* Default MTU */
#define SIXP_MTU 256
/* Default MTU */
enum
sixpack_flags
{
enum
sixpack_flags
{
SIXPF_INUSE
,
/* Channel in use */
SIXPF_ERROR
,
/* Parity, etc. error */
SIXPF_ERROR
,
/* Parity, etc. error */
};
};
struct
sixpack
{
struct
sixpack
{
int
magic
;
/* Various fields. */
/* Various fields. */
struct
tty_struct
*
tty
;
/* ptr to TTY structure
*/
struct
tty_struct
*
tty
;
/* ptr to TTY structure */
struct
net_device
*
dev
;
/* easy for intr handling
*/
struct
net_device
*
dev
;
/* easy for intr handling
*/
/* These are pointers to the malloc()ed frame buffers. */
/* These are pointers to the malloc()ed frame buffers. */
unsigned
char
*
rbuff
;
/* receiver buffer
*/
unsigned
char
*
rbuff
;
/* receiver buffer */
int
rcount
;
/* received chars counter
*/
int
rcount
;
/* received chars counter */
unsigned
char
*
xbuff
;
/* transmitter buffer
*/
unsigned
char
*
xbuff
;
/* transmitter buffer */
unsigned
char
*
xhead
;
/*
pointer to
next byte to XMIT */
unsigned
char
*
xhead
;
/* next byte to XMIT */
int
xleft
;
/* bytes left in XMIT queue
*/
int
xleft
;
/* bytes left in XMIT queue */
unsigned
char
raw_buf
[
4
];
unsigned
char
raw_buf
[
4
];
unsigned
char
cooked_buf
[
400
];
unsigned
char
cooked_buf
[
400
];
...
@@ -105,11 +103,11 @@ struct sixpack {
...
@@ -105,11 +103,11 @@ struct sixpack {
/* 6pack interface statistics. */
/* 6pack interface statistics. */
struct
net_device_stats
stats
;
struct
net_device_stats
stats
;
int
mtu
;
/* Our mtu (to spot changes!)
*/
int
mtu
;
/* Our mtu (to spot changes!) */
int
buffsize
;
/* Max buffers sizes
*/
int
buffsize
;
/* Max buffers sizes */
unsigned
long
flags
;
/* Flag values/ mode etc
*/
unsigned
long
flags
;
/* Flag values/ mode etc
*/
unsigned
char
mode
;
/* 6pack mode
*/
unsigned
char
mode
;
/* 6pack mode
*/
/* 6pack stuff */
/* 6pack stuff */
unsigned
char
tx_delay
;
unsigned
char
tx_delay
;
...
@@ -125,112 +123,293 @@ struct sixpack {
...
@@ -125,112 +123,293 @@ struct sixpack {
struct
timer_list
tx_t
;
struct
timer_list
tx_t
;
struct
timer_list
resync_t
;
struct
timer_list
resync_t
;
atomic_t
refcnt
;
struct
semaphore
dead_sem
;
spinlock_t
lock
;
};
};
#define AX25_6PACK_HEADER_LEN 0
#define AX25_6PACK_HEADER_LEN 0
#define SIXPACK_MAGIC 0x5304
typedef
struct
sixpack_ctrl
{
struct
sixpack
ctrl
;
/* 6pack things */
struct
net_device
dev
;
/* the device */
}
sixpack_ctrl_t
;
static
sixpack_ctrl_t
**
sixpack_ctrls
;
int
sixpack_maxdev
=
SIXP_NRUNIT
;
/* Can be overridden with insmod! */
MODULE_PARM
(
sixpack_maxdev
,
"i"
);
MODULE_PARM_DESC
(
sixpack_maxdev
,
"number of 6PACK devices"
);
static
void
sp_start_tx_timer
(
struct
sixpack
*
);
static
void
sp_start_tx_timer
(
struct
sixpack
*
);
static
void
sp_xmit_on_air
(
unsigned
long
);
static
void
resync_tnc
(
unsigned
long
);
static
void
sixpack_decode
(
struct
sixpack
*
,
unsigned
char
[],
int
);
static
void
sixpack_decode
(
struct
sixpack
*
,
unsigned
char
[],
int
);
static
int
encode_sixpack
(
unsigned
char
*
,
unsigned
char
*
,
int
,
unsigned
char
);
static
int
encode_sixpack
(
unsigned
char
*
,
unsigned
char
*
,
int
,
unsigned
char
);
static
int
sixpack_init
(
struct
net_device
*
dev
);
static
int
sixpack_init
(
struct
net_device
*
dev
);
static
void
decode_prio_command
(
unsigned
char
,
struct
sixpack
*
);
/*
static
void
decode_std_command
(
unsigned
char
,
struct
sixpack
*
);
* perform the persistence/slottime algorithm for CSMA access. If the
static
void
decode_data
(
unsigned
char
,
struct
sixpack
*
);
* persistence check was successful, write the data to the serial driver.
* Note that in case of DAMA operation, the data is not sent here.
*/
static
int
tnc_init
(
struct
sixpack
*
);
static
void
sp_xmit_on_air
(
unsigned
long
channel
)
{
struct
sixpack
*
sp
=
(
struct
sixpack
*
)
channel
;
int
actual
;
static
unsigned
char
random
;
/* Find a free 6pack channel, and link in this `tty' line. */
random
=
random
*
17
+
41
;
static
inline
struct
sixpack
*
sp_alloc
(
void
)
if
(((
sp
->
status1
&
SIXP_DCD_MASK
)
==
0
)
&&
(
random
<
sp
->
persistence
))
{
sp
->
led_state
=
0x70
;
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
&
sp
->
led_state
,
1
);
sp
->
tx_enable
=
1
;
actual
=
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
sp
->
xbuff
,
sp
->
status2
);
sp
->
xleft
-=
actual
;
sp
->
xhead
+=
actual
;
sp
->
led_state
=
0x60
;
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
&
sp
->
led_state
,
1
);
sp
->
status2
=
0
;
}
else
sp_start_tx_timer
(
sp
);
}
/* ----> 6pack timer interrupt handler and friends. <---- */
static
void
sp_start_tx_timer
(
struct
sixpack
*
sp
)
{
{
sixpack_ctrl_t
*
spp
=
NULL
;
int
when
=
sp
->
slottime
;
int
i
;
for
(
i
=
0
;
i
<
sixpack_maxdev
;
i
++
)
{
del_timer
(
&
sp
->
tx_t
);
spp
=
sixpack_ctrls
[
i
];
sp
->
tx_t
.
data
=
(
unsigned
long
)
sp
;
sp
->
tx_t
.
function
=
sp_xmit_on_air
;
sp
->
tx_t
.
expires
=
jiffies
+
((
when
+
1
)
*
HZ
)
/
100
;
add_timer
(
&
sp
->
tx_t
);
}
if
(
spp
==
NULL
)
/* Encapsulate one AX.25 frame and stuff into a TTY queue. */
break
;
static
void
sp_encaps
(
struct
sixpack
*
sp
,
unsigned
char
*
icp
,
int
len
)
{
unsigned
char
*
msg
,
*
p
=
icp
;
int
actual
,
count
;
if
(
!
test_and_set_bit
(
SIXPF_INUSE
,
&
spp
->
ctrl
.
flags
))
if
(
len
>
sp
->
mtu
)
{
/* sp->mtu = AX25_MTU = max. PACLEN = 256 */
break
;
msg
=
"oversized transmit packet!"
;
goto
out_drop
;
}
}
/* Too many devices... */
if
(
p
[
0
]
>
5
)
{
if
(
i
>=
sixpack_maxdev
)
msg
=
"invalid KISS command"
;
return
NULL
;
goto
out_drop
;
}
/* If no channels are available, allocate one */
if
((
p
[
0
]
!=
0
)
&&
(
len
>
2
))
{
if
(
!
spp
&&
msg
=
"KISS control packet too long"
;
(
sixpack_ctrls
[
i
]
=
(
sixpack_ctrl_t
*
)
kmalloc
(
sizeof
(
sixpack_ctrl_t
),
goto
out_drop
;
GFP_KERNEL
))
!=
NULL
)
{
spp
=
sixpack_ctrls
[
i
];
}
}
memset
(
spp
,
0
,
sizeof
(
sixpack_ctrl_t
));
if
((
p
[
0
]
==
0
)
&&
(
len
<
15
))
{
/* Initialize channel control data */
msg
=
"bad AX.25 packet to transmit"
;
set_bit
(
SIXPF_INUSE
,
&
spp
->
ctrl
.
flags
);
goto
out_drop
;
spp
->
ctrl
.
tty
=
NULL
;
sprintf
(
spp
->
dev
.
name
,
"sp%d"
,
i
);
spp
->
dev
.
base_addr
=
i
;
spp
->
dev
.
priv
=
(
void
*
)
&
spp
->
ctrl
;
spp
->
dev
.
next
=
NULL
;
spp
->
dev
.
init
=
sixpack_init
;
if
(
spp
!=
NULL
)
{
/* register device so that it can be ifconfig'ed */
/* sixpack_init() will be called as a side-effect */
/* SIDE-EFFECT WARNING: sixpack_init() CLEARS spp->ctrl ! */
if
(
register_netdev
(
&
spp
->
dev
)
==
0
)
{
set_bit
(
SIXPF_INUSE
,
&
spp
->
ctrl
.
flags
);
spp
->
ctrl
.
dev
=
&
spp
->
dev
;
spp
->
dev
.
priv
=
(
void
*
)
&
spp
->
ctrl
;
SET_MODULE_OWNER
(
&
spp
->
dev
);
return
&
spp
->
ctrl
;
}
else
{
clear_bit
(
SIXPF_INUSE
,
&
spp
->
ctrl
.
flags
);
printk
(
KERN_WARNING
"sp_alloc() - register_netdev() failure.
\n
"
);
}
}
}
return
NULL
;
count
=
encode_sixpack
(
p
,
sp
->
xbuff
,
len
,
sp
->
tx_delay
);
set_bit
(
TTY_DO_WRITE_WAKEUP
,
&
sp
->
tty
->
flags
);
switch
(
p
[
0
])
{
case
1
:
sp
->
tx_delay
=
p
[
1
];
return
;
case
2
:
sp
->
persistence
=
p
[
1
];
return
;
case
3
:
sp
->
slottime
=
p
[
1
];
return
;
case
4
:
/* ignored */
return
;
case
5
:
sp
->
duplex
=
p
[
1
];
return
;
}
if
(
p
[
0
]
!=
0
)
return
;
/*
* In case of fullduplex or DAMA operation, we don't take care about the
* state of the DCD or of any timers, as the determination of the
* correct time to send is the job of the AX.25 layer. We send
* immediately after data has arrived.
*/
if
(
sp
->
duplex
==
1
)
{
sp
->
led_state
=
0x70
;
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
&
sp
->
led_state
,
1
);
sp
->
tx_enable
=
1
;
actual
=
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
sp
->
xbuff
,
count
);
sp
->
xleft
=
count
-
actual
;
sp
->
xhead
=
sp
->
xbuff
+
actual
;
sp
->
led_state
=
0x60
;
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
&
sp
->
led_state
,
1
);
}
else
{
sp
->
xleft
=
count
;
sp
->
xhead
=
sp
->
xbuff
;
sp
->
status2
=
count
;
if
(
sp
->
duplex
==
0
)
sp_start_tx_timer
(
sp
);
}
return
;
out_drop:
sp
->
stats
.
tx_dropped
++
;
netif_start_queue
(
sp
->
dev
);
printk
(
KERN_DEBUG
"%s: %s - dropped.
\n
"
,
sp
->
dev
->
name
,
msg
);
return
;
}
/* Encapsulate an IP datagram and kick it into a TTY queue. */
static
int
sp_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
{
struct
sixpack
*
sp
=
netdev_priv
(
dev
);
spin_lock_bh
(
&
sp
->
lock
);
/* We were not busy, so we are now... :-) */
netif_stop_queue
(
dev
);
sp
->
stats
.
tx_bytes
+=
skb
->
len
;
sp_encaps
(
sp
,
skb
->
data
,
skb
->
len
);
spin_unlock_bh
(
&
sp
->
lock
);
dev_kfree_skb
(
skb
);
return
0
;
}
static
int
sp_open_dev
(
struct
net_device
*
dev
)
{
struct
sixpack
*
sp
=
netdev_priv
(
dev
);
if
(
sp
->
tty
==
NULL
)
return
-
ENODEV
;
return
0
;
}
}
/* Close the low-level part of the 6pack channel. */
static
int
sp_close
(
struct
net_device
*
dev
)
{
struct
sixpack
*
sp
=
netdev_priv
(
dev
);
spin_lock_bh
(
&
sp
->
lock
);
if
(
sp
->
tty
)
{
/* TTY discipline is running. */
clear_bit
(
TTY_DO_WRITE_WAKEUP
,
&
sp
->
tty
->
flags
);
}
netif_stop_queue
(
dev
);
spin_unlock_bh
(
&
sp
->
lock
);
return
0
;
}
/* Return the frame type ID */
static
int
sp_header
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
,
unsigned
short
type
,
void
*
daddr
,
void
*
saddr
,
unsigned
len
)
{
#ifdef CONFIG_INET
if
(
type
!=
htons
(
ETH_P_AX25
))
return
ax25_encapsulate
(
skb
,
dev
,
type
,
daddr
,
saddr
,
len
);
#endif
return
0
;
}
static
struct
net_device_stats
*
sp_get_stats
(
struct
net_device
*
dev
)
{
struct
sixpack
*
sp
=
netdev_priv
(
dev
);
return
&
sp
->
stats
;
}
static
int
sp_set_dev_mac_address
(
struct
net_device
*
dev
,
void
*
addr
)
{
struct
sockaddr
*
sa
=
addr
;
memcpy
(
dev
->
dev_addr
,
sa
->
sa_data
,
AX25_ADDR_LEN
);
return
0
;
}
static
int
sp_rebuild_header
(
struct
sk_buff
*
skb
)
{
#ifdef CONFIG_INET
return
ax25_rebuild_header
(
skb
);
#else
return
0
;
#endif
}
static
void
sp_setup
(
struct
net_device
*
dev
)
{
static
char
ax25_bcast
[
AX25_ADDR_LEN
]
=
{
'Q'
<<
1
,
'S'
<<
1
,
'T'
<<
1
,
' '
<<
1
,
' '
<<
1
,
' '
<<
1
,
'0'
<<
1
};
static
char
ax25_test
[
AX25_ADDR_LEN
]
=
{
'L'
<<
1
,
'I'
<<
1
,
'N'
<<
1
,
'U'
<<
1
,
'X'
<<
1
,
' '
<<
1
,
'1'
<<
1
};
/* Finish setting up the DEVICE info. */
dev
->
init
=
sixpack_init
;
dev
->
mtu
=
SIXP_MTU
;
dev
->
hard_start_xmit
=
sp_xmit
;
dev
->
open
=
sp_open_dev
;
dev
->
destructor
=
free_netdev
;
dev
->
stop
=
sp_close
;
dev
->
hard_header
=
sp_header
;
dev
->
get_stats
=
sp_get_stats
;
dev
->
set_mac_address
=
sp_set_dev_mac_address
;
dev
->
hard_header_len
=
AX25_MAX_HEADER_LEN
;
dev
->
addr_len
=
AX25_ADDR_LEN
;
dev
->
type
=
ARPHRD_AX25
;
dev
->
tx_queue_len
=
10
;
dev
->
rebuild_header
=
sp_rebuild_header
;
dev
->
tx_timeout
=
NULL
;
/* Only activated in AX.25 mode */
memcpy
(
dev
->
broadcast
,
ax25_bcast
,
AX25_ADDR_LEN
);
memcpy
(
dev
->
dev_addr
,
ax25_test
,
AX25_ADDR_LEN
);
SET_MODULE_OWNER
(
dev
);
/* New-style flags. */
dev
->
flags
=
0
;
}
/* Find a free 6pack channel, and link in this `tty' line. */
static
inline
struct
sixpack
*
sp_alloc
(
void
)
{
struct
sixpack
*
sp
=
NULL
;
struct
net_device
*
dev
=
NULL
;
dev
=
alloc_netdev
(
sizeof
(
struct
sixpack
),
"sp%d"
,
sp_setup
);
if
(
!
dev
)
return
NULL
;
sp
=
netdev_priv
(
dev
);
sp
->
dev
=
dev
;
spin_lock_init
(
&
sp
->
lock
);
if
(
register_netdev
(
dev
))
goto
out_free
;
return
sp
;
out_free:
printk
(
KERN_WARNING
"sp_alloc() - register_netdev() failure.
\n
"
);
free_netdev
(
dev
);
return
NULL
;
}
/* Free a 6pack channel. */
/* Free a 6pack channel. */
static
inline
void
sp_free
(
struct
sixpack
*
sp
)
static
inline
void
sp_free
(
struct
sixpack
*
sp
)
{
{
void
*
tmp
;
/* Free all 6pack frame buffers. */
/* Free all 6pack frame buffers. */
if
(
sp
->
rbuff
)
if
((
tmp
=
xchg
(
&
sp
->
rbuff
,
NULL
))
!=
NULL
)
kfree
(
sp
->
rbuff
);
kfree
(
tmp
);
sp
->
rbuff
=
NULL
;
if
((
tmp
=
xchg
(
&
sp
->
xbuff
,
NULL
))
!=
NULL
)
if
(
sp
->
xbuff
)
kfree
(
tmp
);
kfree
(
sp
->
xbuff
);
sp
->
xbuff
=
NULL
;
if
(
!
test_and_clear_bit
(
SIXPF_INUSE
,
&
sp
->
flags
))
printk
(
KERN_WARNING
"%s: sp_free for already free unit.
\n
"
,
sp
->
dev
->
name
);
}
}
/* Send one completely decapsulated IP datagram to the IP layer. */
/* Send one completely decapsulated IP datagram to the IP layer. */
/* This is the routine that sends the received data to the kernel AX.25.
/*
'cmd' is the KISS command. For AX.25 data, it is zero. */
* This is the routine that sends the received data to the kernel AX.25.
* 'cmd' is the KISS command. For AX.25 data, it is zero.
*/
static
void
sp_bump
(
struct
sixpack
*
sp
,
char
cmd
)
static
void
sp_bump
(
struct
sixpack
*
sp
,
char
cmd
)
{
{
...
@@ -238,98 +417,60 @@ static void sp_bump(struct sixpack *sp, char cmd)
...
@@ -238,98 +417,60 @@ static void sp_bump(struct sixpack *sp, char cmd)
int
count
;
int
count
;
unsigned
char
*
ptr
;
unsigned
char
*
ptr
;
count
=
sp
->
rcount
+
1
;
count
=
sp
->
rcount
+
1
;
sp
->
stats
.
rx_bytes
+=
count
;
sp
->
stats
.
rx_bytes
+=
count
;
if
((
skb
=
dev_alloc_skb
(
count
))
==
NULL
)
{
if
((
skb
=
dev_alloc_skb
(
count
))
==
NULL
)
printk
(
KERN_DEBUG
"%s: memory squeeze, dropping packet.
\n
"
,
sp
->
dev
->
name
);
goto
out_mem
;
sp
->
stats
.
rx_dropped
++
;
return
;
}
skb
->
dev
=
sp
->
dev
;
skb
->
dev
=
sp
->
dev
;
ptr
=
skb_put
(
skb
,
count
);
ptr
=
skb_put
(
skb
,
count
);
*
ptr
++
=
cmd
;
/* KISS command */
*
ptr
++
=
cmd
;
/* KISS command */
memcpy
(
ptr
,
(
sp
->
cooked_buf
)
+
1
,
count
);
memcpy
(
ptr
,
sp
->
cooked_buf
+
1
,
count
);
skb
->
mac
.
raw
=
skb
->
data
;
skb
->
mac
.
raw
=
skb
->
data
;
skb
->
protocol
=
htons
(
ETH_P_AX25
);
skb
->
protocol
=
htons
(
ETH_P_AX25
);
netif_rx
(
skb
);
netif_rx
(
skb
);
sp
->
dev
->
last_rx
=
jiffies
;
sp
->
dev
->
last_rx
=
jiffies
;
sp
->
stats
.
rx_packets
++
;
sp
->
stats
.
rx_packets
++
;
return
;
out_mem:
sp
->
stats
.
rx_dropped
++
;
}
}
/* ----------------------------------------------------------------------- */
/* ----------------------------------------------------------------------- */
/* Encapsulate one AX.25 frame and stuff into a TTY queue. */
/*
static
void
sp_encaps
(
struct
sixpack
*
sp
,
unsigned
char
*
icp
,
int
len
)
* We have a potential race on dereferencing tty->disc_data, because the tty
* layer provides no locking at all - thus one cpu could be running
* sixpack_receive_buf while another calls sixpack_close, which zeroes
* tty->disc_data and frees the memory that sixpack_receive_buf is using. The
* best way to fix this is to use a rwlock in the tty struct, but for now we
* use a single global rwlock for all ttys in ppp line discipline.
*/
static
rwlock_t
disc_data_lock
=
RW_LOCK_UNLOCKED
;
static
struct
sixpack
*
sp_get
(
struct
tty_struct
*
tty
)
{
{
unsigned
char
*
p
;
struct
sixpack
*
sp
;
int
actual
,
count
;
if
(
len
>
sp
->
mtu
)
{
/* sp->mtu = AX25_MTU = max. PACLEN = 256 */
printk
(
KERN_DEBUG
"%s: truncating oversized transmit packet!
\n
"
,
sp
->
dev
->
name
);
sp
->
stats
.
tx_dropped
++
;
netif_start_queue
(
sp
->
dev
);
return
;
}
p
=
icp
;
read_lock
(
&
disc_data_lock
);
sp
=
tty
->
disc_data
;
if
(
sp
)
atomic_inc
(
&
sp
->
refcnt
);
read_unlock
(
&
disc_data_lock
);
if
(
p
[
0
]
>
5
)
{
return
sp
;
printk
(
KERN_DEBUG
"%s: invalid KISS command -- dropped
\n
"
,
sp
->
dev
->
name
);
}
netif_start_queue
(
sp
->
dev
);
return
;
}
if
((
p
[
0
]
!=
0
)
&&
(
len
>
2
))
{
printk
(
KERN_DEBUG
"%s: KISS control packet too long -- dropped
\n
"
,
sp
->
dev
->
name
);
netif_start_queue
(
sp
->
dev
);
return
;
}
if
((
p
[
0
]
==
0
)
&&
(
len
<
15
))
{
printk
(
KERN_DEBUG
"%s: bad AX.25 packet to transmit -- dropped
\n
"
,
sp
->
dev
->
name
);
netif_start_queue
(
sp
->
dev
);
sp
->
stats
.
tx_dropped
++
;
return
;
}
count
=
encode_sixpack
(
p
,
(
unsigned
char
*
)
sp
->
xbuff
,
len
,
sp
->
tx_delay
);
sp
->
tty
->
flags
|=
(
1
<<
TTY_DO_WRITE_WAKEUP
);
switch
(
p
[
0
])
{
case
1
:
sp
->
tx_delay
=
p
[
1
];
return
;
case
2
:
sp
->
persistence
=
p
[
1
];
return
;
case
3
:
sp
->
slottime
=
p
[
1
];
return
;
case
4
:
/* ignored */
return
;
case
5
:
sp
->
duplex
=
p
[
1
];
return
;
}
if
(
p
[
0
]
==
0
)
{
static
void
sp_put
(
struct
sixpack
*
sp
)
/* in case of fullduplex or DAMA operation, we don't take care
{
about the state of the DCD or of any timers, as the determination
if
(
atomic_dec_and_test
(
&
sp
->
refcnt
))
of the correct time to send is the job of the AX.25 layer. We send
up
(
&
sp
->
dead_sem
);
immediately after data has arrived. */
if
(
sp
->
duplex
==
1
)
{
sp
->
led_state
=
0x70
;
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
&
sp
->
led_state
,
1
);
sp
->
tx_enable
=
1
;
actual
=
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
sp
->
xbuff
,
count
);
sp
->
xleft
=
count
-
actual
;
sp
->
xhead
=
sp
->
xbuff
+
actual
;
sp
->
led_state
=
0x60
;
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
&
sp
->
led_state
,
1
);
}
else
{
sp
->
xleft
=
count
;
sp
->
xhead
=
sp
->
xbuff
;
sp
->
status2
=
count
;
if
(
sp
->
duplex
==
0
)
sp_start_tx_timer
(
sp
);
}
}
}
}
/*
/*
...
@@ -338,22 +479,17 @@ static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len)
...
@@ -338,22 +479,17 @@ static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len)
*/
*/
static
void
sixpack_write_wakeup
(
struct
tty_struct
*
tty
)
static
void
sixpack_write_wakeup
(
struct
tty_struct
*
tty
)
{
{
struct
sixpack
*
sp
=
sp_get
(
tty
);
int
actual
;
int
actual
;
struct
sixpack
*
sp
=
(
struct
sixpack
*
)
tty
->
disc_data
;
/* First make sure we're connected. */
if
(
!
sp
||
sp
->
magic
!=
SIXPACK_MAGIC
||
!
netif_running
(
sp
->
dev
))
return
;
if
(
sp
->
xleft
<=
0
)
{
if
(
sp
->
xleft
<=
0
)
{
/* Now serial buffer is almost free & we can start
/* Now serial buffer is almost free & we can start
* transmission of another packet */
* transmission of another packet */
sp
->
stats
.
tx_packets
++
;
sp
->
stats
.
tx_packets
++
;
tty
->
flags
&=
~
(
1
<<
TTY_DO_WRITE_WAKEUP
);
clear_bit
(
TTY_DO_WRITE_WAKEUP
,
&
tty
->
flags
);
sp
->
tx_enable
=
0
;
sp
->
tx_enable
=
0
;
netif_wake_queue
(
sp
->
dev
);
netif_wake_queue
(
sp
->
dev
);
return
;
goto
out
;
}
}
if
(
sp
->
tx_enable
==
1
)
{
if
(
sp
->
tx_enable
==
1
)
{
...
@@ -361,79 +497,34 @@ static void sixpack_write_wakeup(struct tty_struct *tty)
...
@@ -361,79 +497,34 @@ static void sixpack_write_wakeup(struct tty_struct *tty)
sp
->
xleft
-=
actual
;
sp
->
xleft
-=
actual
;
sp
->
xhead
+=
actual
;
sp
->
xhead
+=
actual
;
}
}
}
/* ----------------------------------------------------------------------- */
/* Encapsulate an IP datagram and kick it into a TTY queue. */
static
int
sp_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
out:
{
sp_put
(
sp
);
struct
sixpack
*
sp
=
(
struct
sixpack
*
)
dev
->
priv
;
/* We were not busy, so we are now... :-) */
netif_stop_queue
(
dev
);
sp
->
stats
.
tx_bytes
+=
skb
->
len
;
sp_encaps
(
sp
,
skb
->
data
,
skb
->
len
);
dev_kfree_skb
(
skb
);
return
0
;
}
}
/* ----------------------------------------------------------------------- */
/* perform the persistence/slottime algorithm for CSMA access. If the persistence
/* Open the low-level part of the 6pack channel. */
check was successful, write the data to the serial driver. Note that in case
static
int
sp_open
(
struct
net_device
*
dev
)
of DAMA operation, the data is not sent here. */
static
void
sp_xmit_on_air
(
unsigned
long
channel
)
{
{
struct
sixpack
*
sp
=
(
struct
sixpack
*
)
channel
;
struct
sixpack
*
sp
=
netdev_priv
(
dev
);
int
actual
;
char
*
rbuff
,
*
xbuff
=
NULL
;
static
unsigned
char
random
;
int
err
=
-
ENOBUFS
;
unsigned
long
len
;
random
=
random
*
17
+
41
;
if
(((
sp
->
status1
&
SIXP_DCD_MASK
)
==
0
)
&&
(
random
<
sp
->
persistence
))
{
sp
->
led_state
=
0x70
;
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
&
sp
->
led_state
,
1
);
sp
->
tx_enable
=
1
;
actual
=
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
sp
->
xbuff
,
sp
->
status2
);
sp
->
xleft
-=
actual
;
sp
->
xhead
+=
actual
;
sp
->
led_state
=
0x60
;
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
&
sp
->
led_state
,
1
);
sp
->
status2
=
0
;
}
else
sp_start_tx_timer
(
sp
);
}
/* !!! length of the buffers. MTU is IP MTU, not PACLEN! */
/* Return the frame type ID */
len
=
dev
->
mtu
*
2
;
static
int
sp_header
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
,
unsigned
short
type
,
void
*
daddr
,
void
*
saddr
,
unsigned
len
)
{
#ifdef CONFIG_INET
if
(
type
!=
htons
(
ETH_P_AX25
))
return
ax25_encapsulate
(
skb
,
dev
,
type
,
daddr
,
saddr
,
len
);
#endif
return
0
;
}
rbuff
=
kmalloc
(
len
+
4
,
GFP_KERNEL
);
if
(
rbuff
==
NULL
)
goto
err_exit
;
static
int
sp_rebuild_header
(
struct
sk_buff
*
skb
)
xbuff
=
kmalloc
(
len
+
4
,
GFP_KERNEL
);
{
if
(
xbuff
==
NULL
)
#ifdef CONFIG_INET
goto
err_exit
;
return
ax25_rebuild_header
(
skb
);
#else
return
0
;
#endif
}
spin_lock_bh
(
&
sp
->
lock
);
/* Open the low-level part of the 6pack channel. */
static
int
sp_open
(
struct
net_device
*
dev
)
{
struct
sixpack
*
sp
=
(
struct
sixpack
*
)
dev
->
priv
;
unsigned
long
len
;
if
(
sp
->
tty
==
NULL
)
if
(
sp
->
tty
==
NULL
)
return
-
ENODEV
;
return
-
ENODEV
;
...
@@ -445,18 +536,8 @@ static int sp_open(struct net_device *dev)
...
@@ -445,18 +536,8 @@ static int sp_open(struct net_device *dev)
* xbuff Transmit buffer.
* xbuff Transmit buffer.
*/
*/
/* !!! length of the buffers. MTU is IP MTU, not PACLEN!
rbuff
=
xchg
(
&
sp
->
rbuff
,
rbuff
);
*/
xbuff
=
xchg
(
&
sp
->
xbuff
,
xbuff
);
len
=
dev
->
mtu
*
2
;
if
((
sp
->
rbuff
=
kmalloc
(
len
+
4
,
GFP_KERNEL
))
==
NULL
)
return
-
ENOMEM
;
if
((
sp
->
xbuff
=
kmalloc
(
len
+
4
,
GFP_KERNEL
))
==
NULL
)
{
kfree
(
sp
->
rbuff
);
return
-
ENOMEM
;
}
sp
->
mtu
=
AX25_MTU
+
73
;
sp
->
mtu
=
AX25_MTU
+
73
;
sp
->
buffsize
=
len
;
sp
->
buffsize
=
len
;
...
@@ -465,7 +546,7 @@ static int sp_open(struct net_device *dev)
...
@@ -465,7 +546,7 @@ static int sp_open(struct net_device *dev)
sp
->
rx_count_cooked
=
0
;
sp
->
rx_count_cooked
=
0
;
sp
->
xleft
=
0
;
sp
->
xleft
=
0
;
sp
->
flags
&=
(
1
<<
SIXPF_INUSE
);
/* Clear ESCAPE & ERROR flags */
sp
->
flags
=
0
;
/* Clear ESCAPE & ERROR flags */
sp
->
duplex
=
0
;
sp
->
duplex
=
0
;
sp
->
tx_delay
=
SIXP_TXDELAY
;
sp
->
tx_delay
=
SIXP_TXDELAY
;
...
@@ -482,49 +563,47 @@ static int sp_open(struct net_device *dev)
...
@@ -482,49 +563,47 @@ static int sp_open(struct net_device *dev)
init_timer
(
&
sp
->
tx_t
);
init_timer
(
&
sp
->
tx_t
);
init_timer
(
&
sp
->
resync_t
);
init_timer
(
&
sp
->
resync_t
);
return
0
;
}
/* Close the low-level part of the 6pack channel. */
static
int
sp_close
(
struct
net_device
*
dev
)
{
struct
sixpack
*
sp
=
(
struct
sixpack
*
)
dev
->
priv
;
if
(
sp
->
tty
==
NULL
)
spin_unlock_bh
(
&
sp
->
lock
);
return
-
EBUSY
;
sp
->
tty
->
flags
&=
~
(
1
<<
TTY_DO_WRITE_WAKEUP
)
;
err
=
0
;
netif_stop_queue
(
dev
);
err_exit:
return
0
;
if
(
xbuff
)
kfree
(
xbuff
);
if
(
rbuff
)
kfree
(
rbuff
);
return
err
;
}
}
static
int
sixpack_receive_room
(
struct
tty_struct
*
tty
)
static
int
sixpack_receive_room
(
struct
tty_struct
*
tty
)
{
{
return
65536
;
/* We can handle an infinite amount of data. :-) */
return
65536
;
/* We can handle an infinite amount of data. :-) */
}
}
/* !!! receive state machine */
/*
/*
* Handle the 'receiver data ready' interrupt.
* Handle the 'receiver data ready' interrupt.
* This function is called by the 'tty_io' module in the kernel when
* This function is called by the 'tty_io' module in the kernel when
* a block of 6pack data has been received, which can now be decapsulated
* a block of 6pack data has been received, which can now be decapsulated
* and sent on to some IP layer for further processing.
* and sent on to some IP layer for further processing.
*/
*/
static
void
sixpack_receive_buf
(
struct
tty_struct
*
tty
,
const
unsigned
char
*
cp
,
char
*
fp
,
int
count
)
static
void
sixpack_receive_buf
(
struct
tty_struct
*
tty
,
const
unsigned
char
*
cp
,
char
*
fp
,
int
count
)
{
{
struct
sixpack
*
sp
;
unsigned
char
buf
[
512
];
unsigned
char
buf
[
512
];
int
count1
;
int
count1
;
struct
sixpack
*
sp
=
(
struct
sixpack
*
)
tty
->
disc_data
;
if
(
!
count
)
return
;
if
(
!
sp
||
sp
->
magic
!=
SIXPACK_MAGIC
||
sp
=
sp_get
(
tty
);
!
netif_running
(
sp
->
dev
)
||
!
count
)
if
(
!
sp
)
return
;
return
;
memcpy
(
buf
,
cp
,
count
<
sizeof
(
buf
)
?
count
:
sizeof
(
buf
));
memcpy
(
buf
,
cp
,
count
<
sizeof
(
buf
)
?
count
:
sizeof
(
buf
));
/* Read the characters out of the buffer */
/* Read the characters out of the buffer */
...
@@ -538,6 +617,67 @@ static void sixpack_receive_buf(struct tty_struct *tty, const unsigned char *cp,
...
@@ -538,6 +617,67 @@ static void sixpack_receive_buf(struct tty_struct *tty, const unsigned char *cp,
}
}
}
}
sixpack_decode
(
sp
,
buf
,
count1
);
sixpack_decode
(
sp
,
buf
,
count1
);
sp_put
(
sp
);
if
(
test_and_clear_bit
(
TTY_THROTTLED
,
&
tty
->
flags
)
&&
tty
->
driver
->
unthrottle
)
tty
->
driver
->
unthrottle
(
tty
);
}
/*
* Try to resync the TNC. Called by the resync timer defined in
* decode_prio_command
*/
static
void
resync_tnc
(
unsigned
long
channel
)
{
struct
sixpack
*
sp
=
(
struct
sixpack
*
)
channel
;
struct
net_device
*
dev
=
sp
->
dev
;
static
char
resync_cmd
=
0xe8
;
printk
(
KERN_INFO
"%s: resyncing TNC
\n
"
,
dev
->
name
);
/* clear any data that might have been received */
sp
->
rx_count
=
0
;
sp
->
rx_count_cooked
=
0
;
/* reset state machine */
sp
->
status
=
1
;
sp
->
status1
=
1
;
sp
->
status2
=
0
;
sp
->
tnc_ok
=
0
;
/* resync the TNC */
sp
->
led_state
=
0x60
;
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
&
sp
->
led_state
,
1
);
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
&
resync_cmd
,
1
);
/* Start resync timer again -- the TNC might be still absent */
del_timer
(
&
sp
->
resync_t
);
sp
->
resync_t
.
data
=
(
unsigned
long
)
sp
;
sp
->
resync_t
.
function
=
resync_tnc
;
sp
->
resync_t
.
expires
=
jiffies
+
SIXP_RESYNC_TIMEOUT
;
add_timer
(
&
sp
->
resync_t
);
}
static
inline
int
tnc_init
(
struct
sixpack
*
sp
)
{
unsigned
char
inbyte
=
0xe8
;
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
&
inbyte
,
1
);
del_timer
(
&
sp
->
resync_t
);
sp
->
resync_t
.
data
=
(
unsigned
long
)
sp
;
sp
->
resync_t
.
function
=
resync_tnc
;
sp
->
resync_t
.
expires
=
jiffies
+
SIXP_RESYNC_TIMEOUT
;
add_timer
(
&
sp
->
resync_t
);
return
0
;
}
}
/*
/*
...
@@ -549,37 +689,33 @@ static void sixpack_receive_buf(struct tty_struct *tty, const unsigned char *cp,
...
@@ -549,37 +689,33 @@ static void sixpack_receive_buf(struct tty_struct *tty, const unsigned char *cp,
*/
*/
static
int
sixpack_open
(
struct
tty_struct
*
tty
)
static
int
sixpack_open
(
struct
tty_struct
*
tty
)
{
{
struct
sixpack
*
sp
=
(
struct
sixpack
*
)
tty
->
disc_data
;
struct
sixpack
*
sp
;
int
err
;
int
err
=
0
;
/* First make sure we're not already connected. */
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
if
(
sp
&&
sp
->
magic
==
SIXPACK_MAGIC
)
sp
=
sp_alloc
();
return
-
EEXIST
;
if
(
!
sp
)
{
err
=
-
ENOMEM
;
goto
out
;
}
/* OK. Find a free 6pack channel to use. */
if
((
sp
=
sp_alloc
())
==
NULL
)
return
-
ENFILE
;
sp
->
tty
=
tty
;
sp
->
tty
=
tty
;
tty
->
disc_data
=
sp
;
atomic_set
(
&
sp
->
refcnt
,
1
);
if
(
tty
->
driver
->
flush_buffer
)
init_MUTEX_LOCKED
(
&
sp
->
dead_sem
);
tty
->
driver
->
flush_buffer
(
tty
);
if
(
tty
->
ldisc
.
flush_buffer
)
tty
->
ldisc
.
flush_buffer
(
tty
);
/* Restore default settings */
sp
->
dev
->
type
=
ARPHRD_AX25
;
/* Perform the low-level 6pack initialization. */
/* Perform the low-level 6pack initialization. */
if
((
err
=
sp_open
(
sp
->
dev
)))
if
((
err
=
sp_open
(
sp
->
dev
)))
return
err
;
goto
out
;
/* Done. We have linked the TTY line to a channel. */
/* Done. We have linked the TTY line to a channel. */
tty
->
disc_data
=
sp
;
tnc_init
(
sp
);
tnc_init
(
sp
);
return
sp
->
dev
->
base_addr
;
out:
return
err
;
}
}
...
@@ -593,102 +729,93 @@ static void sixpack_close(struct tty_struct *tty)
...
@@ -593,102 +729,93 @@ static void sixpack_close(struct tty_struct *tty)
{
{
struct
sixpack
*
sp
=
(
struct
sixpack
*
)
tty
->
disc_data
;
struct
sixpack
*
sp
=
(
struct
sixpack
*
)
tty
->
disc_data
;
/* First make sure we're connected. */
write_lock
(
&
disc_data_lock
);
if
(
!
sp
||
sp
->
magic
!=
SIXPACK_MAGIC
)
sp
=
tty
->
disc_data
;
tty
->
disc_data
=
0
;
write_unlock
(
&
disc_data_lock
);
if
(
sp
==
0
)
return
;
return
;
rtnl_lock
();
/*
dev_close
(
sp
->
dev
);
* We have now ensured that nobody can start using ap from now on, but
* we have to wait for all existing users to finish.
*/
if
(
!
atomic_dec_and_test
(
&
sp
->
refcnt
))
down
(
&
sp
->
dead_sem
);
del_timer
(
&
sp
->
tx_t
);
del_timer
(
&
sp
->
tx_t
);
del_timer
(
&
sp
->
resync_t
);
del_timer
(
&
sp
->
resync_t
);
tty
->
disc_data
=
0
;
sp
->
tty
=
NULL
;
sp_free
(
sp
);
sp_free
(
sp
);
unregister_netdevice
(
sp
->
dev
);
unregister_netdev
(
sp
->
dev
);
rtnl_unlock
();
}
static
struct
net_device_stats
*
sp_get_stats
(
struct
net_device
*
dev
)
{
struct
sixpack
*
sp
=
(
struct
sixpack
*
)
dev
->
priv
;
return
&
sp
->
stats
;
}
}
static
int
sp_set_mac_address
(
struct
net_device
*
dev
,
void
*
addr
)
static
int
sp_set_mac_address
(
struct
net_device
*
dev
,
void
*
addr
)
{
{
return
copy_from_user
(
dev
->
dev_addr
,
addr
,
AX25_ADDR_LEN
)
?
-
EFAULT
:
0
;
return
copy_from_user
(
dev
->
dev_addr
,
addr
,
AX25_ADDR_LEN
)
?
-
EFAULT
:
0
;
}
}
static
int
sp_set_dev_mac_address
(
struct
net_device
*
dev
,
void
*
addr
)
{
struct
sockaddr
*
sa
=
addr
;
memcpy
(
dev
->
dev_addr
,
sa
->
sa_data
,
AX25_ADDR_LEN
);
return
0
;
}
/* Perform I/O control on an active 6pack channel. */
/* Perform I/O control on an active 6pack channel. */
static
int
sixpack_ioctl
(
struct
tty_struct
*
tty
,
void
*
file
,
int
cmd
,
void
*
arg
)
static
int
sixpack_ioctl
(
struct
tty_struct
*
tty
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
{
struct
sixpack
*
sp
=
(
struct
sixpack
*
)
tty
->
disc_data
;
struct
sixpack
*
sp
=
sp_get
(
tty
)
;
unsigned
int
tmp
;
unsigned
int
tmp
,
err
;
/* First make sure we're connected. */
if
(
!
sp
)
if
(
!
sp
||
sp
->
magic
!=
SIXPACK_MAGIC
)
return
-
ENXIO
;
return
-
EINVAL
;
switch
(
cmd
)
{
switch
(
cmd
)
{
case
SIOCGIFNAME
:
case
SIOCGIFNAME
:
return
copy_to_user
(
arg
,
sp
->
dev
->
name
,
strlen
(
sp
->
dev
->
name
)
+
1
)
?
-
EFAULT
:
0
;
err
=
copy_to_user
((
void
*
)
arg
,
sp
->
dev
->
name
,
strlen
(
sp
->
dev
->
name
)
+
1
)
?
-
EFAULT
:
0
;
break
;
case
SIOCGIFENCAP
:
case
SIOCGIFENCAP
:
return
put_user
(
0
,
(
int
*
)
arg
);
err
=
put_user
(
0
,
(
int
*
)
arg
);
break
;
case
SIOCSIFENCAP
:
case
SIOCSIFENCAP
:
if
(
get_user
(
tmp
,
(
int
*
)
arg
))
if
(
get_user
(
tmp
,
(
int
*
)
arg
))
{
return
-
EFAULT
;
err
=
-
EFAULT
;
break
;
}
sp
->
mode
=
tmp
;
sp
->
mode
=
tmp
;
sp
->
dev
->
addr_len
=
AX25_ADDR_LEN
;
/* sizeof an AX.25 addr */
sp
->
dev
->
addr_len
=
AX25_ADDR_LEN
;
/* sizeof an AX.25 addr */
sp
->
dev
->
hard_header_len
=
AX25_KISS_HEADER_LEN
+
AX25_MAX_HEADER_LEN
+
3
;
sp
->
dev
->
hard_header_len
=
AX25_KISS_HEADER_LEN
+
AX25_MAX_HEADER_LEN
+
3
;
sp
->
dev
->
type
=
ARPHRD_AX25
;
sp
->
dev
->
type
=
ARPHRD_AX25
;
return
0
;
err
=
0
;
break
;
case
SIOCSIFHWADDR
:
case
SIOCSIFHWADDR
:
return
sp_set_mac_address
(
sp
->
dev
,
arg
);
err
=
sp_set_mac_address
(
sp
->
dev
,
(
void
*
)
arg
);
break
;
/* Allow stty to read, but not set, the serial port */
/* Allow stty to read, but not set, the serial port */
case
TCGETS
:
case
TCGETS
:
case
TCGETA
:
case
TCGETA
:
return
n_tty_ioctl
(
tty
,
(
struct
file
*
)
file
,
cmd
,
(
unsigned
long
)
arg
);
err
=
n_tty_ioctl
(
tty
,
(
struct
file
*
)
file
,
cmd
,
arg
);
break
;
default:
default:
return
-
ENOIOCTLCMD
;
return
-
ENOIOCTLCMD
;
}
}
}
static
int
sp_open_dev
(
struct
net_device
*
dev
)
sp_put
(
sp
);
{
struct
sixpack
*
sp
=
(
struct
sixpack
*
)
dev
->
priv
;
return
err
;
if
(
sp
->
tty
==
NULL
)
return
-
ENODEV
;
return
0
;
}
}
/* Fill in our line protocol discipline */
/* Fill in our line protocol discipline */
static
struct
tty_ldisc
sp_ldisc
=
{
static
struct
tty_ldisc
sp_ldisc
=
{
.
magic
=
TTY_LDISC_MAGIC
,
.
owner
=
THIS_MODULE
,
.
magic
=
TTY_LDISC_MAGIC
,
.
name
=
"6pack"
,
.
name
=
"6pack"
,
.
open
=
sixpack_open
,
.
open
=
sixpack_open
,
.
close
=
sixpack_close
,
.
close
=
sixpack_close
,
.
ioctl
=
(
int
(
*
)(
struct
tty_struct
*
,
struct
file
*
,
.
ioctl
=
sixpack_ioctl
,
unsigned
int
,
unsigned
long
))
sixpack_ioctl
,
.
receive_buf
=
sixpack_receive_buf
,
.
receive_buf
=
sixpack_receive_buf
,
.
receive_room
=
sixpack_receive_room
,
.
receive_room
=
sixpack_receive_room
,
.
write_wakeup
=
sixpack_write_wakeup
,
.
write_wakeup
=
sixpack_write_wakeup
,
...
@@ -696,34 +823,18 @@ static struct tty_ldisc sp_ldisc = {
...
@@ -696,34 +823,18 @@ static struct tty_ldisc sp_ldisc = {
/* Initialize 6pack control device -- register 6pack line discipline */
/* Initialize 6pack control device -- register 6pack line discipline */
static
char
msg_banner
[]
__initdata
=
KERN_INFO
"AX.25: 6pack driver, "
SIXPACK_VERSION
" (dynamic channels, max=%d)
\n
"
;
static
char
msg_banner
[]
__initdata
=
KERN_INFO
"AX.25: 6pack driver, "
SIXPACK_VERSION
"
\n
"
;
static
char
msg_nomem
[]
__initdata
=
KERN_ERR
"6pack: can't allocate sixpack_ctrls[] array! No 6pack available.
\n
"
;
static
char
msg_regfail
[]
__initdata
=
KERN_ERR
"6pack: can't register line discipline (err = %d)
\n
"
;
static
char
msg_regfail
[]
__initdata
=
KERN_ERR
"6pack: can't register line discipline (err = %d)
\n
"
;
static
int
__init
sixpack_init_driver
(
void
)
static
int
__init
sixpack_init_driver
(
void
)
{
{
int
status
;
int
status
;
/* Do sanity checks on maximum device parameter. */
printk
(
msg_banner
);
if
(
sixpack_maxdev
<
4
)
sixpack_maxdev
=
4
;
printk
(
msg_banner
,
sixpack_maxdev
);
sixpack_ctrls
=
(
sixpack_ctrl_t
**
)
kmalloc
(
sizeof
(
void
*
)
*
sixpack_maxdev
,
GFP_KERNEL
);
if
(
sixpack_ctrls
==
NULL
)
{
printk
(
msg_nomem
);
return
-
ENOMEM
;
}
/* Clear the pointer array, we allocate devices when we need them */
memset
(
sixpack_ctrls
,
0
,
sizeof
(
void
*
)
*
sixpack_maxdev
);
/* Pointers */
/* Register the provided line protocol discipline */
/* Register the provided line protocol discipline */
if
((
status
=
tty_register_ldisc
(
N_6PACK
,
&
sp_ldisc
))
!=
0
)
{
if
((
status
=
tty_register_ldisc
(
N_6PACK
,
&
sp_ldisc
))
!=
0
)
printk
(
msg_regfail
,
status
);
printk
(
msg_regfail
,
status
);
kfree
(
sixpack_ctrls
);
}
return
status
;
return
status
;
}
}
...
@@ -732,36 +843,16 @@ static const char msg_unregfail[] __exitdata = KERN_ERR "6pack: can't unregister
...
@@ -732,36 +843,16 @@ static const char msg_unregfail[] __exitdata = KERN_ERR "6pack: can't unregister
static
void
__exit
sixpack_exit_driver
(
void
)
static
void
__exit
sixpack_exit_driver
(
void
)
{
{
int
i
;
int
ret
;
if
((
i
=
tty_register_ldisc
(
N_6PACK
,
NULL
)))
printk
(
msg_unregfail
,
i
);
for
(
i
=
0
;
i
<
sixpack_maxdev
;
i
++
)
{
if
((
ret
=
tty_register_ldisc
(
N_6PACK
,
NULL
)))
if
(
sixpack_ctrls
[
i
])
{
printk
(
msg_unregfail
,
ret
);
/*
* VSV = if dev->start==0, then device
* unregistered while close proc.
*/
if
(
netif_running
(
&
sixpack_ctrls
[
i
]
->
dev
))
unregister_netdev
(
&
sixpack_ctrls
[
i
]
->
dev
);
kfree
(
sixpack_ctrls
[
i
]);
}
}
kfree
(
sixpack_ctrls
);
}
}
/* Initialize the 6pack driver. Called by DDI. */
/* Initialize the 6pack driver. Called by DDI. */
static
int
sixpack_init
(
struct
net_device
*
dev
)
static
int
sixpack_init
(
struct
net_device
*
dev
)
{
{
struct
sixpack
*
sp
=
(
struct
sixpack
*
)
dev
->
priv
;
struct
sixpack
*
sp
=
netdev_priv
(
dev
);
static
char
ax25_bcast
[
AX25_ADDR_LEN
]
=
{
'Q'
<<
1
,
'S'
<<
1
,
'T'
<<
1
,
' '
<<
1
,
' '
<<
1
,
' '
<<
1
,
'0'
<<
1
};
static
char
ax25_test
[
AX25_ADDR_LEN
]
=
{
'L'
<<
1
,
'I'
<<
1
,
'N'
<<
1
,
'U'
<<
1
,
'X'
<<
1
,
' '
<<
1
,
'1'
<<
1
};
if
(
sp
==
NULL
)
/* Allocation failed ?? */
if
(
sp
==
NULL
)
/* Allocation failed ?? */
return
-
ENODEV
;
return
-
ENODEV
;
...
@@ -769,52 +860,15 @@ static int sixpack_init(struct net_device *dev)
...
@@ -769,52 +860,15 @@ static int sixpack_init(struct net_device *dev)
/* Set up the "6pack Control Block". (And clear statistics) */
/* Set up the "6pack Control Block". (And clear statistics) */
memset
(
sp
,
0
,
sizeof
(
struct
sixpack
));
memset
(
sp
,
0
,
sizeof
(
struct
sixpack
));
sp
->
magic
=
SIXPACK_MAGIC
;
sp
->
dev
=
dev
;
sp
->
dev
=
dev
;
/* Finish setting up the DEVICE info. */
dev
->
mtu
=
SIXP_MTU
;
dev
->
hard_start_xmit
=
sp_xmit
;
dev
->
open
=
sp_open_dev
;
dev
->
stop
=
sp_close
;
dev
->
hard_header
=
sp_header
;
dev
->
get_stats
=
sp_get_stats
;
dev
->
set_mac_address
=
sp_set_dev_mac_address
;
dev
->
hard_header_len
=
AX25_MAX_HEADER_LEN
;
dev
->
addr_len
=
AX25_ADDR_LEN
;
dev
->
type
=
ARPHRD_AX25
;
dev
->
tx_queue_len
=
10
;
dev
->
rebuild_header
=
sp_rebuild_header
;
dev
->
tx_timeout
=
NULL
;
memcpy
(
dev
->
broadcast
,
ax25_bcast
,
AX25_ADDR_LEN
);
/* Only activated in AX.25 mode */
memcpy
(
dev
->
dev_addr
,
ax25_test
,
AX25_ADDR_LEN
);
/* "" "" "" "" */
/* New-style flags. */
dev
->
flags
=
0
;
return
0
;
return
0
;
}
}
/* ----> 6pack timer interrupt handler and friends. <---- */
static
void
sp_start_tx_timer
(
struct
sixpack
*
sp
)
{
int
when
=
sp
->
slottime
;
del_timer
(
&
sp
->
tx_t
);
sp
->
tx_t
.
data
=
(
unsigned
long
)
sp
;
sp
->
tx_t
.
function
=
sp_xmit_on_air
;
sp
->
tx_t
.
expires
=
jiffies
+
((
when
+
1
)
*
HZ
)
/
100
;
add_timer
(
&
sp
->
tx_t
);
}
/* encode an AX.25 packet into 6pack */
/* encode an AX.25 packet into 6pack */
static
int
encode_sixpack
(
unsigned
char
*
tx_buf
,
unsigned
char
*
tx_buf_raw
,
int
length
,
unsigned
char
tx_delay
)
static
int
encode_sixpack
(
unsigned
char
*
tx_buf
,
unsigned
char
*
tx_buf_raw
,
int
length
,
unsigned
char
tx_delay
)
{
{
int
count
=
0
;
int
count
=
0
;
unsigned
char
checksum
=
0
,
buf
[
400
];
unsigned
char
checksum
=
0
,
buf
[
400
];
...
@@ -849,47 +903,28 @@ static int encode_sixpack(unsigned char *tx_buf, unsigned char *tx_buf_raw, int
...
@@ -849,47 +903,28 @@ static int encode_sixpack(unsigned char *tx_buf, unsigned char *tx_buf_raw, int
return
raw_count
;
return
raw_count
;
}
}
/* decode 4 sixpack-encoded bytes into 3 data bytes */
/* decode a 6pack packet */
static
void
decode_data
(
unsigned
char
inbyte
,
struct
sixpack
*
sp
)
static
void
sixpack_decode
(
struct
sixpack
*
sp
,
unsigned
char
pre_rbuff
[],
int
count
)
{
unsigned
char
inbyte
;
int
count1
;
for
(
count1
=
0
;
count1
<
count
;
count1
++
)
{
inbyte
=
pre_rbuff
[
count1
];
if
(
inbyte
==
SIXP_FOUND_TNC
)
{
printk
(
KERN_INFO
"6pack: TNC found.
\n
"
);
sp
->
tnc_ok
=
1
;
del_timer
(
&
sp
->
resync_t
);
}
if
((
inbyte
&
SIXP_PRIO_CMD_MASK
)
!=
0
)
decode_prio_command
(
inbyte
,
sp
);
else
if
((
inbyte
&
SIXP_STD_CMD_MASK
)
!=
0
)
decode_std_command
(
inbyte
,
sp
);
else
if
((
sp
->
status
&
SIXP_RX_DCD_MASK
)
==
SIXP_RX_DCD_MASK
)
decode_data
(
inbyte
,
sp
);
}
}
static
int
tnc_init
(
struct
sixpack
*
sp
)
{
{
unsigned
char
inbyte
=
0xe8
;
unsigned
char
*
buf
;
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
&
inbyte
,
1
);
if
(
sp
->
rx_count
!=
3
)
{
sp
->
raw_buf
[
sp
->
rx_count
++
]
=
inbyte
;
del_timer
(
&
sp
->
resync_t
);
return
;
sp
->
resync_t
.
data
=
(
unsigned
long
)
sp
;
}
sp
->
resync_t
.
function
=
resync_tnc
;
sp
->
resync_t
.
expires
=
jiffies
+
SIXP_RESYNC_TIMEOUT
;
add_timer
(
&
sp
->
resync_t
);
return
0
;
buf
=
sp
->
raw_buf
;
sp
->
cooked_buf
[
sp
->
rx_count_cooked
++
]
=
buf
[
0
]
|
((
buf
[
1
]
<<
2
)
&
0xc0
);
sp
->
cooked_buf
[
sp
->
rx_count_cooked
++
]
=
(
buf
[
1
]
&
0x0f
)
|
((
buf
[
2
]
<<
2
)
&
0xf0
);
sp
->
cooked_buf
[
sp
->
rx_count_cooked
++
]
=
(
buf
[
2
]
&
0x03
)
|
(
inbyte
<<
2
);
sp
->
rx_count
=
0
;
}
}
/* identify and execute a 6pack priority command byte */
/* identify and execute a 6pack priority command byte */
static
void
decode_prio_command
(
unsigned
char
cmd
,
struct
sixpack
*
sp
)
static
void
decode_prio_command
(
unsigned
char
cmd
,
struct
sixpack
*
sp
)
...
@@ -916,8 +951,7 @@ static void decode_prio_command(unsigned char cmd, struct sixpack *sp)
...
@@ -916,8 +951,7 @@ static void decode_prio_command(unsigned char cmd, struct sixpack *sp)
cmd
&=
!
SIXP_RX_DCD_MASK
;
cmd
&=
!
SIXP_RX_DCD_MASK
;
}
}
sp
->
status
=
cmd
&
SIXP_PRIO_DATA_MASK
;
sp
->
status
=
cmd
&
SIXP_PRIO_DATA_MASK
;
}
}
else
{
/* output watchdog char if idle */
else
{
/* output watchdog char if idle */
if
((
sp
->
status2
!=
0
)
&&
(
sp
->
duplex
==
1
))
{
if
((
sp
->
status2
!=
0
)
&&
(
sp
->
duplex
==
1
))
{
sp
->
led_state
=
0x70
;
sp
->
led_state
=
0x70
;
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
&
sp
->
led_state
,
1
);
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
&
sp
->
led_state
,
1
);
...
@@ -948,46 +982,6 @@ static void decode_prio_command(unsigned char cmd, struct sixpack *sp)
...
@@ -948,46 +982,6 @@ static void decode_prio_command(unsigned char cmd, struct sixpack *sp)
sp
->
status1
=
cmd
&
SIXP_PRIO_DATA_MASK
;
sp
->
status1
=
cmd
&
SIXP_PRIO_DATA_MASK
;
}
}
/* try to resync the TNC. Called by the resync timer defined in
decode_prio_command */
static
void
resync_tnc
(
unsigned
long
channel
)
{
static
char
resync_cmd
=
0xe8
;
struct
sixpack
*
sp
=
(
struct
sixpack
*
)
channel
;
printk
(
KERN_INFO
"6pack: resyncing TNC
\n
"
);
/* clear any data that might have been received */
sp
->
rx_count
=
0
;
sp
->
rx_count_cooked
=
0
;
/* reset state machine */
sp
->
status
=
1
;
sp
->
status1
=
1
;
sp
->
status2
=
0
;
sp
->
tnc_ok
=
0
;
/* resync the TNC */
sp
->
led_state
=
0x60
;
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
&
sp
->
led_state
,
1
);
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
&
resync_cmd
,
1
);
/* Start resync timer again -- the TNC might be still absent */
del_timer
(
&
sp
->
resync_t
);
sp
->
resync_t
.
data
=
(
unsigned
long
)
sp
;
sp
->
resync_t
.
function
=
resync_tnc
;
sp
->
resync_t
.
expires
=
jiffies
+
SIXP_RESYNC_TIMEOUT
;
add_timer
(
&
sp
->
resync_t
);
}
/* identify and execute a standard 6pack command byte */
/* identify and execute a standard 6pack command byte */
static
void
decode_std_command
(
unsigned
char
cmd
,
struct
sixpack
*
sp
)
static
void
decode_std_command
(
unsigned
char
cmd
,
struct
sixpack
*
sp
)
...
@@ -997,67 +991,70 @@ static void decode_std_command(unsigned char cmd, struct sixpack *sp)
...
@@ -997,67 +991,70 @@ static void decode_std_command(unsigned char cmd, struct sixpack *sp)
channel
=
cmd
&
SIXP_CHN_MASK
;
channel
=
cmd
&
SIXP_CHN_MASK
;
switch
(
cmd
&
SIXP_CMD_MASK
)
{
/* normal command */
switch
(
cmd
&
SIXP_CMD_MASK
)
{
/* normal command */
case
SIXP_SEOF
:
case
SIXP_SEOF
:
if
((
sp
->
rx_count
==
0
)
&&
(
sp
->
rx_count_cooked
==
0
))
{
if
((
sp
->
rx_count
==
0
)
&&
(
sp
->
rx_count_cooked
==
0
))
{
if
((
sp
->
status
&
SIXP_RX_DCD_MASK
)
==
if
((
sp
->
status
&
SIXP_RX_DCD_MASK
)
==
SIXP_RX_DCD_MASK
)
{
SIXP_RX_DCD_MASK
)
{
sp
->
led_state
=
0x68
;
sp
->
led_state
=
0x68
;
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
&
sp
->
led_state
,
1
);
}
}
else
{
sp
->
led_state
=
0x60
;
/* fill trailing bytes with zeroes */
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
&
sp
->
led_state
,
1
);
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
&
sp
->
led_state
,
1
);
rest
=
sp
->
rx_count
;
if
(
rest
!=
0
)
for
(
i
=
rest
;
i
<=
3
;
i
++
)
decode_data
(
0
,
sp
);
if
(
rest
==
2
)
sp
->
rx_count_cooked
-=
2
;
else
if
(
rest
==
3
)
sp
->
rx_count_cooked
-=
1
;
for
(
i
=
0
;
i
<
sp
->
rx_count_cooked
;
i
++
)
checksum
+=
sp
->
cooked_buf
[
i
];
if
(
checksum
!=
SIXP_CHKSUM
)
{
printk
(
KERN_DEBUG
"6pack: bad checksum %2.2x
\n
"
,
checksum
);
}
else
{
sp
->
rcount
=
sp
->
rx_count_cooked
-
2
;
sp_bump
(
sp
,
0
);
}
sp
->
rx_count_cooked
=
0
;
}
}
break
;
}
else
{
case
SIXP_TX_URUN
:
printk
(
KERN_DEBUG
"6pack: TX underrun
\n
"
);
sp
->
led_state
=
0x60
;
break
;
/* fill trailing bytes with zeroes */
case
SIXP_RX_ORUN
:
printk
(
KERN_DEBUG
"6pack: RX overrun
\n
"
);
sp
->
tty
->
driver
->
write
(
sp
->
tty
,
0
,
&
sp
->
led_state
,
1
);
break
;
rest
=
sp
->
rx_count
;
case
SIXP_RX_BUF_OVL
:
if
(
rest
!=
0
)
printk
(
KERN_DEBUG
"6pack: RX buffer overflow
\n
"
);
for
(
i
=
rest
;
i
<=
3
;
i
++
)
decode_data
(
0
,
sp
);
if
(
rest
==
2
)
sp
->
rx_count_cooked
-=
2
;
else
if
(
rest
==
3
)
sp
->
rx_count_cooked
-=
1
;
for
(
i
=
0
;
i
<
sp
->
rx_count_cooked
;
i
++
)
checksum
+=
sp
->
cooked_buf
[
i
];
if
(
checksum
!=
SIXP_CHKSUM
)
{
printk
(
KERN_DEBUG
"6pack: bad checksum %2.2x
\n
"
,
checksum
);
}
else
{
sp
->
rcount
=
sp
->
rx_count_cooked
-
2
;
sp_bump
(
sp
,
0
);
}
sp
->
rx_count_cooked
=
0
;
}
break
;
case
SIXP_TX_URUN
:
printk
(
KERN_DEBUG
"6pack: TX underrun
\n
"
);
break
;
case
SIXP_RX_ORUN
:
printk
(
KERN_DEBUG
"6pack: RX overrun
\n
"
);
break
;
case
SIXP_RX_BUF_OVL
:
printk
(
KERN_DEBUG
"6pack: RX buffer overflow
\n
"
);
}
}
}
}
/* decode
4 sixpack-encoded bytes into 3 data bytes
*/
/* decode
a 6pack packet
*/
static
void
decode_data
(
unsigned
char
inbyte
,
struct
sixpack
*
sp
)
static
void
sixpack_decode
(
struct
sixpack
*
sp
,
unsigned
char
pre_rbuff
[],
int
count
)
{
{
unsigned
char
*
buf
;
unsigned
char
inbyte
;
int
count1
;
if
(
sp
->
rx_count
!=
3
)
for
(
count1
=
0
;
count1
<
count
;
count1
++
)
{
sp
->
raw_buf
[
sp
->
rx_count
++
]
=
inbyte
;
inbyte
=
pre_rbuff
[
count1
];
else
{
if
(
inbyte
==
SIXP_FOUND_TNC
)
{
buf
=
sp
->
raw_buf
;
printk
(
KERN_INFO
"6pack: TNC found.
\n
"
);
sp
->
cooked_buf
[
sp
->
rx_count_cooked
++
]
=
sp
->
tnc_ok
=
1
;
buf
[
0
]
|
((
buf
[
1
]
<<
2
)
&
0xc0
);
del_timer
(
&
sp
->
resync_t
);
sp
->
cooked_buf
[
sp
->
rx_count_cooked
++
]
=
}
(
buf
[
1
]
&
0x0f
)
|
((
buf
[
2
]
<<
2
)
&
0xf0
);
if
((
inbyte
&
SIXP_PRIO_CMD_MASK
)
!=
0
)
sp
->
cooked_buf
[
sp
->
rx_count_cooked
++
]
=
decode_prio_command
(
inbyte
,
sp
);
(
buf
[
2
]
&
0x03
)
|
(
inbyte
<<
2
);
else
if
((
inbyte
&
SIXP_STD_CMD_MASK
)
!=
0
)
sp
->
rx_count
=
0
;
decode_std_command
(
inbyte
,
sp
);
else
if
((
sp
->
status
&
SIXP_RX_DCD_MASK
)
==
SIXP_RX_DCD_MASK
)
decode_data
(
inbyte
,
sp
);
}
}
}
}
MODULE_AUTHOR
(
"Ralf Baechle DO1GRB <ralf@linux-mips.org>"
);
MODULE_AUTHOR
(
"Andreas Knsgen <ajk@ccac.rwth-aachen.de>"
);
MODULE_DESCRIPTION
(
"6pack driver for AX.25"
);
MODULE_DESCRIPTION
(
"6pack driver for AX.25"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS_LDISC
(
N_6PACK
);
MODULE_ALIAS_LDISC
(
N_6PACK
);
...
...
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