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
b331768e
Commit
b331768e
authored
Sep 18, 2002
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge nuts.ninka.net:/home/davem/src/BK/ham-2.5
into nuts.ninka.net:/home/davem/src/BK/net-2.5
parents
e65ca57c
c2edf826
Changes
41
Hide whitespace changes
Inline
Side-by-side
Showing
41 changed files
with
3971 additions
and
3987 deletions
+3971
-3987
MAINTAINERS
MAINTAINERS
+6
-6
include/net/ax25.h
include/net/ax25.h
+20
-5
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
+830
-731
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/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
+8
-17
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
+308
-315
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 @
b331768e
...
@@ -240,8 +240,8 @@ L: linux-net@vger.kernel.org
...
@@ -240,8 +240,8 @@ L: linux-net@vger.kernel.org
S: Maintained
S: Maintained
AX.25 NETWORK LAYER
AX.25 NETWORK LAYER
P:
Matthias Welwarsky
P:
Ralf Baechle
M:
dg2fef@afthd.tu-darmstadt.de
M:
ralf@linux-mips.org
L: linux-hams@vger.kernel.org
L: linux-hams@vger.kernel.org
S: Maintained
S: Maintained
...
@@ -1121,8 +1121,8 @@ L: netfilter-devel@lists.netfilter.org
...
@@ -1121,8 +1121,8 @@ L: netfilter-devel@lists.netfilter.org
S: Supported
S: Supported
NETROM NETWORK LAYER
NETROM NETWORK LAYER
P:
Tomi Manninen
P:
Ralf Baechle
M:
Tomi.Manninen@hut.fi
M:
ralf@linux-mips.org
L: linux-hams@vger.kernel.org
L: linux-hams@vger.kernel.org
S: Maintained
S: Maintained
...
@@ -1371,8 +1371,8 @@ W: http://www.namesys.com
...
@@ -1371,8 +1371,8 @@ W: http://www.namesys.com
S: Supported
S: Supported
ROSE NETWORK LAYER
ROSE NETWORK LAYER
P:
Jean-Paul Roubelat
P:
Ralf Baechle
M:
jpr@f6fbb
.org
M:
ralf@linux-mips
.org
L: linux-hams@vger.kernel.org
L: linux-hams@vger.kernel.org
S: Maintained
S: Maintained
...
...
include/net/ax25.h
View file @
b331768e
...
@@ -3,11 +3,14 @@
...
@@ -3,11 +3,14 @@
*
*
* Alan Cox (GW4PTS) 10/11/93
* Alan Cox (GW4PTS) 10/11/93
*/
*/
#ifndef _AX25_H
#ifndef _AX25_H
#define _AX25_H
#define _AX25_H
#include <linux/config.h>
#include <linux/config.h>
#include <linux/ax25.h>
#include <linux/ax25.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <asm/atomic.h>
#define AX25_T1CLAMPLO 1
#define AX25_T1CLAMPLO 1
#define AX25_T1CLAMPHI (30 * HZ)
#define AX25_T1CLAMPHI (30 * HZ)
...
@@ -66,6 +69,8 @@
...
@@ -66,6 +69,8 @@
#define AX25_UA 0x63
/* Unnumbered acknowledge */
#define AX25_UA 0x63
/* Unnumbered acknowledge */
#define AX25_FRMR 0x87
/* Frame reject */
#define AX25_FRMR 0x87
/* Frame reject */
#define AX25_UI 0x03
/* Unnumbered information */
#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_PF 0x10
/* Poll/final bit for standard AX.25 */
#define AX25_EPF 0x01
/* Poll/final bit for extended AX.25 */
#define AX25_EPF 0x01
/* Poll/final bit for extended AX.25 */
...
@@ -147,10 +152,12 @@ typedef struct {
...
@@ -147,10 +152,12 @@ typedef struct {
typedef
struct
ax25_route
{
typedef
struct
ax25_route
{
struct
ax25_route
*
next
;
struct
ax25_route
*
next
;
atomic_t
ref
;
ax25_address
callsign
;
ax25_address
callsign
;
struct
net_device
*
dev
;
struct
net_device
*
dev
;
ax25_digi
*
digipeat
;
ax25_digi
*
digipeat
;
char
ip_mode
;
char
ip_mode
;
struct
timer_list
timer
;
}
ax25_route
;
}
ax25_route
;
typedef
struct
{
typedef
struct
{
...
@@ -197,11 +204,12 @@ typedef struct ax25_cb {
...
@@ -197,11 +204,12 @@ typedef struct ax25_cb {
#define ax25_sk(__sk) ((ax25_cb *)(__sk)->protinfo)
#define ax25_sk(__sk) ((ax25_cb *)(__sk)->protinfo)
/* af_ax25.c */
/* 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_free_cb
(
ax25_cb
*
);
extern
void
ax25_insert_socket
(
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_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
ax25_cb
*
ax25_find_cb
(
ax25_address
*
,
ax25_address
*
,
ax25_digi
*
,
struct
net_device
*
);
extern
struct
sock
*
ax25_addr_match
(
ax25_address
*
);
extern
struct
sock
*
ax25_addr_match
(
ax25_address
*
);
extern
void
ax25_send_to_raw
(
struct
sock
*
,
struct
sk_buff
*
,
int
);
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 *);
...
@@ -224,6 +232,7 @@ extern void ax25_digi_invert(ax25_digi *, ax25_digi *);
/* ax25_dev.c */
/* ax25_dev.c */
extern
ax25_dev
*
ax25_dev_list
;
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_dev_ax25dev
(
struct
net_device
*
);
extern
ax25_dev
*
ax25_addr_ax25dev
(
ax25_address
*
);
extern
ax25_dev
*
ax25_addr_ax25dev
(
ax25_address
*
);
extern
void
ax25_dev_device_up
(
struct
net_device
*
);
extern
void
ax25_dev_device_up
(
struct
net_device
*
);
...
@@ -286,10 +295,16 @@ extern void ax25_rt_device_down(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_ioctl
(
unsigned
int
,
void
*
);
extern
int
ax25_rt_get_info
(
char
*
,
char
**
,
off_t
,
int
);
extern
int
ax25_rt_get_info
(
char
*
,
char
**
,
off_t
,
int
);
extern
int
ax25_rt_autobind
(
ax25_cb
*
,
ax25_address
*
);
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
struct
sk_buff
*
ax25_rt_build_path
(
struct
sk_buff
*
,
ax25_address
*
,
ax25_address
*
,
ax25_digi
*
);
extern
void
ax25_rt_free
(
void
);
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 */
/* ax25_std_in.c */
extern
int
ax25_std_frame_in
(
ax25_cb
*
,
struct
sk_buff
*
,
int
);
extern
int
ax25_std_frame_in
(
ax25_cb
*
,
struct
sk_buff
*
,
int
);
...
...
net/ax25/Config.in
View file @
b331768e
#
#
# Amateur Radio protocols and AX.25 device configuration
# Amateur Radio protocols and AX.25 device configuration
#
#
# 19971130 Now in an own category to make correct compilation of the
# 19971130 Now in an own category to make correct compilation of the
# AX.25 stuff easier...
# AX.25 stuff easier...
# Joerg Reuter DL1BKE <jreuter@yaina.de>
# Joerg Reuter DL1BKE <jreuter@yaina.de>
# 19980129 Moved to net/ax25/Config.in, sourcing device drivers.
# 19980129 Moved to net/ax25/Config.in, sourcing device drivers.
...
...
net/ax25/TODO
0 → 100644
View file @
b331768e
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 @
b331768e
/*
/*
* 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
* Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
*
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* This module:
* Copyright (C) Darryl Miles G7LED (dlm@g7led.demon.co.uk)
* This module is free software; you can redistribute it and/or
* Copyright (C) Steven Whitehouse GW7RRM (stevew@acm.org)
* modify it under the terms of the GNU General Public License
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* as published by the Free Software Foundation; either version
* Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
* 2 of the License, or (at your option) any later version.
* Copyright (C) Hans Alblas PE1AYX (hans@esrac.ele.tue.nl)
*
* Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
* 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.
*/
*/
#include <linux/config.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/errno.h>
...
@@ -114,6 +23,7 @@
...
@@ -114,6 +23,7 @@
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/smp_lock.h>
#include <linux/sockios.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/net.h>
#include <net/ax25.h>
#include <net/ax25.h>
...
@@ -134,13 +44,15 @@
...
@@ -134,13 +44,15 @@
#include <linux/netfilter.h>
#include <linux/netfilter.h>
#include <linux/sysctl.h>
#include <linux/sysctl.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <net/tcp.h>
#include <net/tcp.h>
#include <net/ip.h>
#include <net/ip.h>
#include <net/arp.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
;
static
struct
proto_ops
ax25_proto_ops
;
...
@@ -171,27 +83,24 @@ static void ax25_free_sock(struct sock *sk)
...
@@ -171,27 +83,24 @@ static void ax25_free_sock(struct sock *sk)
static
void
ax25_remove_socket
(
ax25_cb
*
ax25
)
static
void
ax25_remove_socket
(
ax25_cb
*
ax25
)
{
{
ax25_cb
*
s
;
ax25_cb
*
s
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
ax25_list_lock
);
if
((
s
=
ax25_list
)
==
ax25
)
{
if
((
s
=
ax25_list
)
==
ax25
)
{
ax25_list
=
s
->
next
;
ax25_list
=
s
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
ax25_list_lock
);
return
;
return
;
}
}
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
if
(
s
->
next
==
ax25
)
{
if
(
s
->
next
==
ax25
)
{
s
->
next
=
ax25
->
next
;
s
->
next
=
ax25
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
ax25_list_lock
);
return
;
return
;
}
}
s
=
s
->
next
;
s
=
s
->
next
;
}
}
spin_unlock_bh
(
&
ax25_list_lock
);
restore_flags
(
flags
);
}
}
/*
/*
...
@@ -205,18 +114,21 @@ static void ax25_kill_by_device(struct net_device *dev)
...
@@ -205,18 +114,21 @@ static void ax25_kill_by_device(struct net_device *dev)
if
((
ax25_dev
=
ax25_dev_ax25dev
(
dev
))
==
NULL
)
if
((
ax25_dev
=
ax25_dev_ax25dev
(
dev
))
==
NULL
)
return
;
return
;
spin_lock_bh
(
&
ax25_list_lock
);
for
(
s
=
ax25_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
for
(
s
=
ax25_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
if
(
s
->
ax25_dev
==
ax25_dev
)
{
if
(
s
->
ax25_dev
==
ax25_dev
)
{
s
->
ax25_dev
=
NULL
;
s
->
ax25_dev
=
NULL
;
ax25_disconnect
(
s
,
ENETUNREACH
);
ax25_disconnect
(
s
,
ENETUNREACH
);
}
}
}
}
spin_unlock_bh
(
&
ax25_list_lock
);
}
}
/*
/*
* Handle device status changes.
* 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
;
struct
net_device
*
dev
=
(
struct
net_device
*
)
ptr
;
...
@@ -225,16 +137,16 @@ static int ax25_device_event(struct notifier_block *this,unsigned long event, vo
...
@@ -225,16 +137,16 @@ static int ax25_device_event(struct notifier_block *this,unsigned long event, vo
return
NOTIFY_DONE
;
return
NOTIFY_DONE
;
switch
(
event
)
{
switch
(
event
)
{
case
NETDEV_UP
:
case
NETDEV_UP
:
ax25_dev_device_up
(
dev
);
ax25_dev_device_up
(
dev
);
break
;
break
;
case
NETDEV_DOWN
:
case
NETDEV_DOWN
:
ax25_kill_by_device
(
dev
);
ax25_kill_by_device
(
dev
);
ax25_rt_device_down
(
dev
);
ax25_rt_device_down
(
dev
);
ax25_dev_device_down
(
dev
);
ax25_dev_device_down
(
dev
);
break
;
break
;
default:
default:
break
;
break
;
}
}
return
NOTIFY_DONE
;
return
NOTIFY_DONE
;
...
@@ -245,64 +157,59 @@ static int ax25_device_event(struct notifier_block *this,unsigned long event, vo
...
@@ -245,64 +157,59 @@ static int ax25_device_event(struct notifier_block *this,unsigned long event, vo
*/
*/
void
ax25_insert_socket
(
ax25_cb
*
ax25
)
void
ax25_insert_socket
(
ax25_cb
*
ax25
)
{
{
unsigned
long
flags
;
spin_lock_bh
(
&
ax25_list_lock
);
save_flags
(
flags
);
cli
();
ax25
->
next
=
ax25_list
;
ax25
->
next
=
ax25_list
;
ax25_list
=
ax25
;
ax25_list
=
ax25
;
spin_unlock_bh
(
&
ax25_list_lock
);
restore_flags
(
flags
);
}
}
/*
/*
* Find a socket that wants to accept the SABM we have just
* Find a socket that wants to accept the SABM we have just
* received.
* 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
;
ax25_cb
*
s
;
save_flags
(
flags
);
spin_lock_bh
(
&
ax25_list_lock
);
cli
();
for
(
s
=
ax25_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
for
(
s
=
ax25_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
if
((
s
->
iamdigi
&&
!
digi
)
||
(
!
s
->
iamdigi
&&
digi
))
if
((
s
->
iamdigi
&&
!
digi
)
||
(
!
s
->
iamdigi
&&
digi
))
continue
;
continue
;
if
(
s
->
sk
!=
NULL
&&
ax25cmp
(
&
s
->
source_addr
,
addr
)
==
0
&&
s
->
sk
->
type
==
type
&&
s
->
sk
->
state
==
TCP_LISTEN
)
{
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 device is null we match any device */
if
(
s
->
ax25_dev
==
NULL
||
s
->
ax25_dev
->
dev
==
dev
)
{
if
(
s
->
ax25_dev
==
NULL
||
s
->
ax25_dev
->
dev
==
dev
)
{
restore_flags
(
flags
);
spin_unlock_bh
(
&
ax25_list_lock
);
return
s
->
sk
;
return
s
->
sk
;
}
}
}
}
}
}
spin_unlock_bh
(
&
ax25_list_lock
);
restore_flags
(
flags
);
return
NULL
;
return
NULL
;
}
}
/*
/*
* Find an AX.25 socket given both ends.
* 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
;
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
)
{
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
)
{
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
);
sk
=
s
->
sk
;
return
s
->
sk
;
lock_sock
(
sk
);
break
;
}
}
}
}
restore_flags
(
flags
);
out:
spin_unlock_bh
(
&
ax25_list_lock
);
return
NULL
;
return
NULL
;
}
}
...
@@ -311,14 +218,12 @@ struct sock *ax25_find_socket(ax25_address *my_addr, ax25_address *dest_addr, in
...
@@ -311,14 +218,12 @@ struct sock *ax25_find_socket(ax25_address *my_addr, ax25_address *dest_addr, in
* Find an AX.25 control block given both ends. It will only pick up
* 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.
* 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
;
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
)
{
for
(
s
=
ax25_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
if
(
s
->
sk
!=
NULL
&&
s
->
sk
->
type
!=
SOCK_SEQPACKET
)
if
(
s
->
sk
!=
NULL
&&
s
->
sk
->
type
!=
SOCK_SEQPACKET
)
continue
;
continue
;
...
@@ -334,12 +239,12 @@ ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, ax25_digi
...
@@ -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
)
if
(
s
->
digipeat
!=
NULL
&&
s
->
digipeat
->
ndigi
!=
0
)
continue
;
continue
;
}
}
restore_flags
(
flags
);
spin_unlock_bh
(
&
ax25_list_lock
);
return
s
;
return
s
;
}
}
}
}
spin_unlock_bh
(
&
ax25_list_lock
);
restore_flags
(
flags
);
return
NULL
;
return
NULL
;
}
}
...
@@ -349,22 +254,21 @@ ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, ax25_digi
...
@@ -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
)
struct
sock
*
ax25_addr_match
(
ax25_address
*
addr
)
{
{
unsigned
long
flags
;
struct
sock
*
sk
=
NULL
;
ax25_cb
*
s
;
ax25_cb
*
s
;
save_flags
(
flags
);
spin_lock_bh
(
&
ax25_list_lock
);
cli
();
for
(
s
=
ax25_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
for
(
s
=
ax25_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
if
(
s
->
sk
!=
NULL
&&
ax25cmp
(
&
s
->
source_addr
,
addr
)
==
0
&&
s
->
sk
->
type
==
SOCK_RAW
)
{
if
(
s
->
sk
!=
NULL
&&
ax25cmp
(
&
s
->
source_addr
,
addr
)
==
0
&&
restore_flags
(
flags
);
s
->
sk
->
type
==
SOCK_RAW
)
{
return
s
->
sk
;
sk
=
s
->
sk
;
lock_sock
(
sk
);
break
;
}
}
}
}
spin_unlock_bh
(
&
ax25_list_lock
);
restore_flags
(
flags
);
return
sk
;
return
NULL
;
}
}
void
ax25_send_to_raw
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
,
int
proto
)
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)
...
@@ -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
* This is called from user mode and the timers. Thus it protects itself
*
interrupt users but doesn't worry about being called during work.
*
against interrupt users but doesn't worry about being called during
*
Once it is removed from the queue no interrupt or bottom half will
*
work. Once it is removed from the queue no interrupt or bottom half
* touch it and we are (fairly 8-) ) safe.
*
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
;
struct
sk_buff
*
skb
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
(
);
ax25_remove_socket
(
ax25
);
ax25_stop_heartbeat
(
ax25
);
ax25_stop_heartbeat
(
ax25
);
ax25_stop_t1timer
(
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
...
@@ -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_t3timer
(
ax25
);
ax25_stop_idletimer
(
ax25
);
ax25_stop_idletimer
(
ax25
);
ax25_remove_socket
(
ax25
);
ax25_clear_queues
(
ax25
);
/* Flush the queues */
ax25_clear_queues
(
ax25
);
/* Flush the queues */
if
(
ax25
->
sk
!=
NULL
)
{
if
(
ax25
->
sk
!=
NULL
)
{
while
((
skb
=
skb_dequeue
(
&
ax25
->
sk
->
receive_queue
))
!=
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
);
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
);
ax25_start_heartbeat
(
sax25
);
sax25
->
state
=
AX25_STATE_0
;
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
...
@@ -450,8 +355,6 @@ void ax25_destroy_socket(ax25_cb *ax25) /* Not static as it's used by the timer
}
else
{
}
else
{
ax25_free_cb
(
ax25
);
ax25_free_cb
(
ax25
);
}
}
restore_flags
(
flags
);
}
}
/*
/*
...
@@ -484,66 +387,66 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg)
...
@@ -484,66 +387,66 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg)
return
-
ENOTCONN
;
return
-
ENOTCONN
;
switch
(
ax25_ctl
.
cmd
)
{
switch
(
ax25_ctl
.
cmd
)
{
case
AX25_KILL
:
case
AX25_KILL
:
ax25_send_control
(
ax25
,
AX25_DISC
,
AX25_POLLON
,
AX25_COMMAND
);
ax25_send_control
(
ax25
,
AX25_DISC
,
AX25_POLLON
,
AX25_COMMAND
);
#ifdef CONFIG_AX25_DAMA_SLAVE
#ifdef CONFIG_AX25_DAMA_SLAVE
if
(
ax25_dev
->
dama
.
slave
&&
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
]
==
AX25_PROTO_DAMA_SLAVE
)
if
(
ax25_dev
->
dama
.
slave
&&
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
]
==
AX25_PROTO_DAMA_SLAVE
)
ax25_dama_off
(
ax25
);
ax25_dama_off
(
ax25
);
#endif
#endif
ax25_disconnect
(
ax25
,
ENETRESET
);
ax25_disconnect
(
ax25
,
ENETRESET
);
break
;
break
;
case
AX25_WINDOW
:
case
AX25_WINDOW
:
if
(
ax25
->
modulus
==
AX25_MODULUS
)
{
if
(
ax25
->
modulus
==
AX25_MODULUS
)
{
if
(
ax25_ctl
.
arg
<
1
||
ax25_ctl
.
arg
>
7
)
if
(
ax25_ctl
.
arg
<
1
||
ax25_ctl
.
arg
>
7
)
return
-
EINVAL
;
return
-
EINVAL
;
}
else
{
}
else
{
if
(
ax25_ctl
.
arg
<
1
||
ax25_ctl
.
arg
>
63
)
if
(
ax25_ctl
.
arg
<
1
||
ax25_ctl
.
arg
>
63
)
return
-
EINVAL
;
}
ax25
->
window
=
ax25_ctl
.
arg
;
break
;
case
AX25_T1
:
if
(
ax25_ctl
.
arg
<
1
)
return
-
EINVAL
;
return
-
EINVAL
;
ax25
->
rtt
=
(
ax25_ctl
.
arg
*
HZ
)
/
2
;
}
ax25
->
t1
=
ax25_ctl
.
arg
*
HZ
;
ax25
->
window
=
ax25_ctl
.
arg
;
break
;
break
;
case
AX25_T2
:
case
AX25_T1
:
if
(
ax25_ctl
.
arg
<
1
)
if
(
ax25_ctl
.
arg
<
1
)
return
-
EINVAL
;
return
-
EINVAL
;
ax25
->
t2
=
ax25_ctl
.
arg
*
HZ
;
ax25
->
rtt
=
(
ax25_ctl
.
arg
*
HZ
)
/
2
;
break
;
ax25
->
t1
=
ax25_ctl
.
arg
*
HZ
;
break
;
case
AX25_N2
:
if
(
ax25_ctl
.
arg
<
1
||
ax25_ctl
.
arg
>
31
)
case
AX25_T2
:
return
-
EINVAL
;
if
(
ax25_ctl
.
arg
<
1
)
ax25
->
n2count
=
0
;
return
-
EINVAL
;
ax25
->
n2
=
ax25_ctl
.
arg
;
ax25
->
t2
=
ax25_ctl
.
arg
*
HZ
;
break
;
break
;
case
AX25_T3
:
case
AX25_N2
:
if
(
ax25_ctl
.
arg
<
0
)
if
(
ax25_ctl
.
arg
<
1
||
ax25_ctl
.
arg
>
31
)
return
-
EINVAL
;
return
-
EINVAL
;
ax25
->
t3
=
ax25_ctl
.
arg
*
HZ
;
ax25
->
n2count
=
0
;
break
;
ax25
->
n2
=
ax25_ctl
.
arg
;
break
;
case
AX25_IDLE
:
if
(
ax25_ctl
.
arg
<
0
)
case
AX25_T3
:
return
-
EINVAL
;
if
(
ax25_ctl
.
arg
<
0
)
ax25
->
idle
=
ax25_ctl
.
arg
*
60
*
HZ
;
return
-
EINVAL
;
break
;
ax25
->
t3
=
ax25_ctl
.
arg
*
HZ
;
break
;
case
AX25_PACLEN
:
if
(
ax25_ctl
.
arg
<
16
||
ax25_ctl
.
arg
>
65535
)
case
AX25_IDLE
:
return
-
EINVAL
;
if
(
ax25_ctl
.
arg
<
0
)
ax25
->
paclen
=
ax25_ctl
.
arg
;
return
-
EINVAL
;
break
;
ax25
->
idle
=
ax25_ctl
.
arg
*
60
*
HZ
;
break
;
default:
return
-
EINVAL
;
case
AX25_PACLEN
:
if
(
ax25_ctl
.
arg
<
16
||
ax25_ctl
.
arg
>
65535
)
return
-
EINVAL
;
ax25
->
paclen
=
ax25_ctl
.
arg
;
break
;
default:
return
-
EINVAL
;
}
}
return
0
;
return
0
;
...
@@ -631,13 +534,14 @@ ax25_cb *ax25_create_cb(void)
...
@@ -631,13 +534,14 @@ ax25_cb *ax25_create_cb(void)
* AX25 socket object
* 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
;
struct
sock
*
sk
=
sock
->
sk
;
ax25_cb
*
ax25
=
ax25_sk
(
sk
)
;
ax25_cb
*
ax25
;
struct
net_device
*
dev
;
struct
net_device
*
dev
;
char
devname
[
IFNAMSIZ
];
char
devname
[
IFNAMSIZ
];
int
opt
;
int
opt
,
res
=
0
;
if
(
level
!=
SOL_AX25
)
if
(
level
!=
SOL_AX25
)
return
-
ENOPROTOOPT
;
return
-
ENOPROTOOPT
;
...
@@ -648,98 +552,131 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, char *op
...
@@ -648,98 +552,131 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, char *op
if
(
get_user
(
opt
,
(
int
*
)
optval
))
if
(
get_user
(
opt
,
(
int
*
)
optval
))
return
-
EFAULT
;
return
-
EFAULT
;
lock_sock
(
sk
);
ax25
=
ax25_sk
(
sk
);
switch
(
optname
)
{
switch
(
optname
)
{
case
AX25_WINDOW
:
case
AX25_WINDOW
:
if
(
ax25
->
modulus
==
AX25_MODULUS
)
{
if
(
ax25
->
modulus
==
AX25_MODULUS
)
{
if
(
opt
<
1
||
opt
>
7
)
if
(
opt
<
1
||
opt
>
7
)
{
return
-
EINVAL
;
res
=
-
EINVAL
;
}
else
{
break
;
if
(
opt
<
1
||
opt
>
63
)
return
-
EINVAL
;
}
}
ax25
->
window
=
opt
;
}
else
{
return
0
;
if
(
opt
<
1
||
opt
>
63
)
{
res
=
-
EINVAL
;
case
AX25_T1
:
break
;
if
(
opt
<
1
)
}
return
-
EINVAL
;
}
ax25
->
rtt
=
(
opt
*
HZ
)
/
2
;
ax25
->
window
=
opt
;
ax25
->
t1
=
opt
*
HZ
;
break
;
return
0
;
case
AX25_T2
:
if
(
opt
<
1
)
return
-
EINVAL
;
ax25
->
t2
=
opt
*
HZ
;
return
0
;
case
AX25_N2
:
if
(
opt
<
1
||
opt
>
31
)
return
-
EINVAL
;
ax25
->
n2
=
opt
;
return
0
;
case
AX25_T3
:
if
(
opt
<
1
)
return
-
EINVAL
;
ax25
->
t3
=
opt
*
HZ
;
return
0
;
case
AX25_IDLE
:
if
(
opt
<
0
)
return
-
EINVAL
;
ax25
->
idle
=
opt
*
60
*
HZ
;
return
0
;
case
AX25_BACKOFF
:
if
(
opt
<
0
||
opt
>
2
)
return
-
EINVAL
;
ax25
->
backoff
=
opt
;
return
0
;
case
AX25_EXTSEQ
:
ax25
->
modulus
=
opt
?
AX25_EMODULUS
:
AX25_MODULUS
;
return
0
;
case
AX25_PIDINCL
:
ax25
->
pidincl
=
opt
?
1
:
0
;
return
0
;
case
AX25_IAMDIGI
:
ax25
->
iamdigi
=
opt
?
1
:
0
;
return
0
;
case
AX25_PACLEN
:
if
(
opt
<
16
||
opt
>
65535
)
return
-
EINVAL
;
ax25
->
paclen
=
opt
;
return
0
;
case
SO_BINDTODEVICE
:
if
(
optlen
>
IFNAMSIZ
)
optlen
=
IFNAMSIZ
;
if
(
copy_from_user
(
devname
,
optval
,
optlen
))
return
-
EFAULT
;
dev
=
dev_get_by_name
(
devname
);
if
(
dev
==
NULL
)
return
-
ENODEV
;
if
(
sk
->
type
==
SOCK_SEQPACKET
&&
(
sock
->
state
!=
SS_UNCONNECTED
||
sk
->
state
==
TCP_LISTEN
))
return
-
EADDRNOTAVAIL
;
ax25
->
ax25_dev
=
ax25_dev_ax25dev
(
dev
);
ax25_fillin_cb
(
ax25
,
ax25
->
ax25_dev
);
return
0
;
default:
case
AX25_T1
:
return
-
ENOPROTOOPT
;
if
(
opt
<
1
)
{
res
=
-
EINVAL
;
break
;
}
ax25
->
rtt
=
(
opt
*
HZ
)
/
2
;
ax25
->
t1
=
opt
*
HZ
;
break
;
case
AX25_T2
:
if
(
opt
<
1
)
{
res
=
-
EINVAL
;
break
;
}
ax25
->
t2
=
opt
*
HZ
;
break
;
case
AX25_N2
:
if
(
opt
<
1
||
opt
>
31
)
{
res
=
-
EINVAL
;
break
;
}
ax25
->
n2
=
opt
;
break
;
case
AX25_T3
:
if
(
opt
<
1
)
{
res
=
-
EINVAL
;
break
;
}
ax25
->
t3
=
opt
*
HZ
;
break
;
case
AX25_IDLE
:
if
(
opt
<
0
)
{
res
=
-
EINVAL
;
break
;
}
ax25
->
idle
=
opt
*
60
*
HZ
;
break
;
case
AX25_BACKOFF
:
if
(
opt
<
0
||
opt
>
2
)
{
res
=
-
EINVAL
;
break
;
}
ax25
->
backoff
=
opt
;
break
;
case
AX25_EXTSEQ
:
ax25
->
modulus
=
opt
?
AX25_EMODULUS
:
AX25_MODULUS
;
break
;
case
AX25_PIDINCL
:
ax25
->
pidincl
=
opt
?
1
:
0
;
break
;
case
AX25_IAMDIGI
:
ax25
->
iamdigi
=
opt
?
1
:
0
;
break
;
case
AX25_PACLEN
:
if
(
opt
<
16
||
opt
>
65535
)
{
res
=
-
EINVAL
;
break
;
}
ax25
->
paclen
=
opt
;
break
;
case
SO_BINDTODEVICE
:
if
(
optlen
>
IFNAMSIZ
)
optlen
=
IFNAMSIZ
;
if
(
copy_from_user
(
devname
,
optval
,
optlen
))
{
res
=
-
EFAULT
;
break
;
}
dev
=
dev_get_by_name
(
devname
);
if
(
dev
==
NULL
)
{
res
=
-
ENODEV
;
break
;
}
if
(
sk
->
type
==
SOCK_SEQPACKET
&&
(
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
);
break
;
default:
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
;
struct
sock
*
sk
=
sock
->
sk
;
ax25_cb
*
ax25
=
ax25_sk
(
sk
)
;
ax25_cb
*
ax25
;
struct
ax25_dev
*
ax25_dev
;
struct
ax25_dev
*
ax25_dev
;
char
devname
[
IFNAMSIZ
];
char
devname
[
IFNAMSIZ
];
void
*
valptr
;
void
*
valptr
;
...
@@ -751,76 +688,81 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op
...
@@ -751,76 +688,81 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op
if
(
get_user
(
maxlen
,
optlen
))
if
(
get_user
(
maxlen
,
optlen
))
return
-
EFAULT
;
return
-
EFAULT
;
if
(
maxlen
<
1
)
if
(
maxlen
<
1
)
return
-
EFAULT
;
return
-
EFAULT
;
valptr
=
(
void
*
)
&
val
;
valptr
=
(
void
*
)
&
val
;
length
=
min_t
(
unsigned
int
,
maxlen
,
sizeof
(
int
));
length
=
min_t
(
unsigned
int
,
maxlen
,
sizeof
(
int
));
lock_sock
(
sk
);
ax25
=
ax25_sk
(
sk
);
switch
(
optname
)
{
switch
(
optname
)
{
case
AX25_WINDOW
:
case
AX25_WINDOW
:
val
=
ax25
->
window
;
val
=
ax25
->
window
;
break
;
break
;
case
AX25_T1
:
case
AX25_T1
:
val
=
ax25
->
t1
/
HZ
;
val
=
ax25
->
t1
/
HZ
;
break
;
break
;
case
AX25_T2
:
case
AX25_T2
:
val
=
ax25
->
t2
/
HZ
;
val
=
ax25
->
t2
/
HZ
;
break
;
break
;
case
AX25_N2
:
case
AX25_N2
:
val
=
ax25
->
n2
;
val
=
ax25
->
n2
;
break
;
break
;
case
AX25_T3
:
case
AX25_T3
:
val
=
ax25
->
t3
/
HZ
;
val
=
ax25
->
t3
/
HZ
;
break
;
break
;
case
AX25_IDLE
:
case
AX25_IDLE
:
val
=
ax25
->
idle
/
(
60
*
HZ
);
val
=
ax25
->
idle
/
(
60
*
HZ
);
break
;
break
;
case
AX25_BACKOFF
:
case
AX25_BACKOFF
:
val
=
ax25
->
backoff
;
val
=
ax25
->
backoff
;
break
;
break
;
case
AX25_EXTSEQ
:
case
AX25_EXTSEQ
:
val
=
(
ax25
->
modulus
==
AX25_EMODULUS
);
val
=
(
ax25
->
modulus
==
AX25_EMODULUS
);
break
;
break
;
case
AX25_PIDINCL
:
case
AX25_PIDINCL
:
val
=
ax25
->
pidincl
;
val
=
ax25
->
pidincl
;
break
;
break
;
case
AX25_IAMDIGI
:
case
AX25_IAMDIGI
:
val
=
ax25
->
iamdigi
;
val
=
ax25
->
iamdigi
;
break
;
break
;
case
AX25_PACLEN
:
case
AX25_PACLEN
:
val
=
ax25
->
paclen
;
val
=
ax25
->
paclen
;
break
;
break
;
case
SO_BINDTODEVICE
:
ax25_dev
=
ax25
->
ax25_dev
;
if
(
ax25_dev
!=
NULL
&&
ax25_dev
->
dev
!=
NULL
)
{
strncpy
(
devname
,
ax25_dev
->
dev
->
name
,
IFNAMSIZ
);
length
=
min_t
(
unsigned
int
,
strlen
(
ax25_dev
->
dev
->
name
)
+
1
,
maxlen
);
devname
[
length
-
1
]
=
'\0'
;
}
else
{
*
devname
=
'\0'
;
length
=
1
;
}
valptr
=
(
void
*
)
devname
;
case
SO_BINDTODEVICE
:
break
;
ax25_dev
=
ax25
->
ax25_dev
;
default:
if
(
ax25_dev
!=
NULL
&&
ax25_dev
->
dev
!=
NULL
)
{
return
-
ENOPROTOOPT
;
strncpy
(
devname
,
ax25_dev
->
dev
->
name
,
IFNAMSIZ
);
length
=
min_t
(
unsigned
int
,
strlen
(
ax25_dev
->
dev
->
name
)
+
1
,
maxlen
);
devname
[
length
-
1
]
=
'\0'
;
}
else
{
*
devname
=
'\0'
;
length
=
1
;
}
valptr
=
(
void
*
)
devname
;
break
;
default:
release_sock
(
sk
);
return
-
ENOPROTOOPT
;
}
}
release_sock
(
sk
);
if
(
put_user
(
length
,
optlen
))
if
(
put_user
(
length
,
optlen
))
return
-
EFAULT
;
return
-
EFAULT
;
...
@@ -831,14 +773,20 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op
...
@@ -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
)
static
int
ax25_listen
(
struct
socket
*
sock
,
int
backlog
)
{
{
struct
sock
*
sk
=
sock
->
sk
;
struct
sock
*
sk
=
sock
->
sk
;
int
res
=
0
;
lock_sock
(
sk
);
if
(
sk
->
type
==
SOCK_SEQPACKET
&&
sk
->
state
!=
TCP_LISTEN
)
{
if
(
sk
->
type
==
SOCK_SEQPACKET
&&
sk
->
state
!=
TCP_LISTEN
)
{
sk
->
max_ack_backlog
=
backlog
;
sk
->
max_ack_backlog
=
backlog
;
sk
->
state
=
TCP_LISTEN
;
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
)
int
ax25_create
(
struct
socket
*
sock
,
int
protocol
)
...
@@ -847,46 +795,48 @@ int ax25_create(struct socket *sock, int protocol)
...
@@ -847,46 +795,48 @@ int ax25_create(struct socket *sock, int protocol)
ax25_cb
*
ax25
;
ax25_cb
*
ax25
;
switch
(
sock
->
type
)
{
switch
(
sock
->
type
)
{
case
SOCK_DGRAM
:
case
SOCK_DGRAM
:
if
(
protocol
==
0
||
protocol
==
PF_AX25
)
if
(
protocol
==
0
||
protocol
==
PF_AX25
)
protocol
=
AX25_P_TEXT
;
protocol
=
AX25_P_TEXT
;
break
;
case
SOCK_SEQPACKET
:
switch
(
protocol
)
{
case
0
:
case
PF_AX25
:
/* For CLX */
protocol
=
AX25_P_TEXT
;
break
;
break
;
case
SOCK_SEQPACKET
:
case
AX25_P_SEGMENT
:
switch
(
protocol
)
{
case
0
:
case
PF_AX25
:
/* For CLX */
protocol
=
AX25_P_TEXT
;
break
;
case
AX25_P_SEGMENT
:
#ifdef CONFIG_INET
#ifdef CONFIG_INET
case
AX25_P_ARP
:
case
AX25_P_ARP
:
case
AX25_P_IP
:
case
AX25_P_IP
:
#endif
#endif
#ifdef CONFIG_NETROM
#ifdef CONFIG_NETROM
case
AX25_P_NETROM
:
case
AX25_P_NETROM
:
#endif
#endif
#ifdef CONFIG_ROSE
#ifdef CONFIG_ROSE
case
AX25_P_ROSE
:
case
AX25_P_ROSE
:
#endif
#endif
return
-
ESOCKTNOSUPPORT
;
return
-
ESOCKTNOSUPPORT
;
#ifdef CONFIG_NETROM_MODULE
#ifdef CONFIG_NETROM_MODULE
case
AX25_P_NETROM
:
case
AX25_P_NETROM
:
if
(
ax25_protocol_is_registered
(
AX25_P_NETROM
))
if
(
ax25_protocol_is_registered
(
AX25_P_NETROM
))
return
-
ESOCKTNOSUPPORT
;
return
-
ESOCKTNOSUPPORT
;
#endif
#endif
#ifdef CONFIG_ROSE_MODULE
#ifdef CONFIG_ROSE_MODULE
case
AX25_P_ROSE
:
case
AX25_P_ROSE
:
if
(
ax25_protocol_is_registered
(
AX25_P_ROSE
))
if
(
ax25_protocol_is_registered
(
AX25_P_ROSE
))
return
-
ESOCKTNOSUPPORT
;
return
-
ESOCKTNOSUPPORT
;
#endif
#endif
default:
break
;
}
break
;
case
SOCK_RAW
:
break
;
default:
default:
return
-
ESOCKTNOSUPPORT
;
break
;
}
break
;
case
SOCK_RAW
:
break
;
default:
return
-
ESOCKTNOSUPPORT
;
}
}
if
((
sk
=
sk_alloc
(
PF_AX25
,
GFP_ATOMIC
,
1
,
NULL
))
==
NULL
)
if
((
sk
=
sk_alloc
(
PF_AX25
,
GFP_ATOMIC
,
1
,
NULL
))
==
NULL
)
...
@@ -923,14 +873,14 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev)
...
@@ -923,14 +873,14 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev)
}
}
switch
(
osk
->
type
)
{
switch
(
osk
->
type
)
{
case
SOCK_DGRAM
:
case
SOCK_DGRAM
:
break
;
break
;
case
SOCK_SEQPACKET
:
case
SOCK_SEQPACKET
:
break
;
break
;
default:
default:
sk_free
(
sk
);
sk_free
(
sk
);
ax25_free_cb
(
ax25
);
ax25_free_cb
(
ax25
);
return
NULL
;
return
NULL
;
}
}
sock_init_data
(
NULL
,
sk
);
sock_init_data
(
NULL
,
sk
);
...
@@ -985,58 +935,61 @@ static int ax25_release(struct socket *sock)
...
@@ -985,58 +935,61 @@ static int ax25_release(struct socket *sock)
struct
sock
*
sk
=
sock
->
sk
;
struct
sock
*
sk
=
sock
->
sk
;
ax25_cb
*
ax25
;
ax25_cb
*
ax25
;
if
(
sk
==
NULL
)
return
0
;
if
(
sk
==
NULL
)
return
0
;
lock_sock
(
sk
);
ax25
=
ax25_sk
(
sk
);
ax25
=
ax25_sk
(
sk
);
if
(
sk
->
type
==
SOCK_SEQPACKET
)
{
if
(
sk
->
type
==
SOCK_SEQPACKET
)
{
switch
(
ax25
->
state
)
{
switch
(
ax25
->
state
)
{
case
AX25_STATE_0
:
case
AX25_STATE_0
:
ax25_disconnect
(
ax25
,
0
);
ax25_disconnect
(
ax25
,
0
);
ax25_destroy_socket
(
ax25
);
ax25_destroy_socket
(
ax25
);
break
;
break
;
case
AX25_STATE_1
:
case
AX25_STATE_1
:
case
AX25_STATE_2
:
case
AX25_STATE_2
:
ax25_send_control
(
ax25
,
AX25_DISC
,
AX25_POLLON
,
AX25_COMMAND
);
ax25_send_control
(
ax25
,
AX25_DISC
,
AX25_POLLON
,
AX25_COMMAND
);
ax25_disconnect
(
ax25
,
0
);
ax25_disconnect
(
ax25
,
0
);
ax25_destroy_socket
(
ax25
);
ax25_destroy_socket
(
ax25
);
break
;
break
;
case
AX25_STATE_3
:
case
AX25_STATE_3
:
case
AX25_STATE_4
:
case
AX25_STATE_4
:
ax25_clear_queues
(
ax25
);
ax25_clear_queues
(
ax25
);
ax25
->
n2count
=
0
;
ax25
->
n2count
=
0
;
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
case
AX25_PROTO_STD_SIMPLEX
:
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
case
AX25_PROTO_STD_DUPLEX
:
case
AX25_PROTO_STD_SIMPLEX
:
ax25_send_control
(
ax25
,
case
AX25_PROTO_STD_DUPLEX
:
AX25_DISC
,
ax25_send_control
(
ax25
,
AX25_POLLON
,
AX25_DISC
,
AX25_COMMAND
);
AX25_POLLON
,
ax25_stop_t2timer
(
ax25
);
AX25_COMMAND
);
ax25_stop_t3timer
(
ax25
);
ax25_stop_t2timer
(
ax25
);
ax25_stop_idletimer
(
ax25
);
ax25_stop_t3timer
(
ax25
);
break
;
ax25_stop_idletimer
(
ax25
);
break
;
#ifdef CONFIG_AX25_DAMA_SLAVE
#ifdef CONFIG_AX25_DAMA_SLAVE
case
AX25_PROTO_DAMA_SLAVE
:
case
AX25_PROTO_DAMA_SLAVE
:
ax25_stop_t3timer
(
ax25
);
ax25_stop_t3timer
(
ax25
);
ax25_stop_idletimer
(
ax25
);
ax25_stop_idletimer
(
ax25
);
break
;
#endif
}
ax25_calculate_t1
(
ax25
);
ax25_start_t1timer
(
ax25
);
ax25
->
state
=
AX25_STATE_2
;
sk
->
state
=
TCP_CLOSE
;
sk
->
shutdown
|=
SEND_SHUTDOWN
;
sk
->
state_change
(
sk
);
sk
->
dead
=
1
;
sk
->
destroy
=
1
;
break
;
break
;
#endif
}
ax25_calculate_t1
(
ax25
);
ax25_start_t1timer
(
ax25
);
ax25
->
state
=
AX25_STATE_2
;
sk
->
state
=
TCP_CLOSE
;
sk
->
shutdown
|=
SEND_SHUTDOWN
;
sk
->
state_change
(
sk
);
sk
->
dead
=
1
;
sk
->
destroy
=
1
;
break
;
default:
default:
break
;
break
;
}
}
}
else
{
}
else
{
sk
->
state
=
TCP_CLOSE
;
sk
->
state
=
TCP_CLOSE
;
...
@@ -1046,8 +999,9 @@ static int ax25_release(struct socket *sock)
...
@@ -1046,8 +999,9 @@ static int ax25_release(struct socket *sock)
ax25_destroy_socket
(
ax25
);
ax25_destroy_socket
(
ax25
);
}
}
sock
->
sk
=
NULL
;
sock
->
sk
=
NULL
;
sk
->
socket
=
NULL
;
/* Not used, but we should do this */
sk
->
socket
=
NULL
;
/* Not used, but we should do this */
release_sock
(
sk
);
return
0
;
return
0
;
}
}
...
@@ -1055,26 +1009,25 @@ static int ax25_release(struct socket *sock)
...
@@ -1055,26 +1009,25 @@ static int ax25_release(struct socket *sock)
/*
/*
* We support a funny extension here so you can (as root) give any callsign
* We support a funny extension here so you can (as root) give any callsign
* digipeated via a local address as source. This hack is obsolete now
* digipeated via a local address as source. This hack is obsolete now
* that we've implemented support for SO_BINDTODEVICE. It is however small
* that we've implemented support for SO_BINDTODEVICE. It is however small
* and trivially backward compatible.
* and trivially backward compatible.
*/
*/
static
int
ax25_bind
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
int
addr_len
)
static
int
ax25_bind
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
int
addr_len
)
{
{
struct
sock
*
sk
=
sock
->
sk
;
struct
sock
*
sk
=
sock
->
sk
;
ax25_cb
*
ax25
=
ax25_sk
(
sk
);
struct
full_sockaddr_ax25
*
addr
=
(
struct
full_sockaddr_ax25
*
)
uaddr
;
struct
full_sockaddr_ax25
*
addr
=
(
struct
full_sockaddr_ax25
*
)
uaddr
;
ax25_address
*
call
;
ax25_dev
*
ax25_dev
=
NULL
;
ax25_dev
*
ax25_dev
=
NULL
;
ax25_address
*
call
;
ax25_cb
*
ax25
;
int
err
=
0
;
if
(
sk
->
zapped
==
0
)
if
(
addr_len
!=
sizeof
(
struct
sockaddr_ax25
)
&&
return
-
EINVAL
;
if
(
addr_len
!=
sizeof
(
struct
sockaddr_ax25
)
&&
addr_len
!=
sizeof
(
struct
full_sockaddr_ax25
))
{
addr_len
!=
sizeof
(
struct
full_sockaddr_ax25
))
{
/* support for old structure may go away some time */
/* support for old structure may go away some time */
if
((
addr_len
<
sizeof
(
struct
sockaddr_ax25
)
+
sizeof
(
ax25_address
)
*
6
)
||
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
;
return
-
EINVAL
;
}
printk
(
KERN_WARNING
"ax25_bind(): %s uses old (6 digipeater) socket structure.
\n
"
,
printk
(
KERN_WARNING
"ax25_bind(): %s uses old (6 digipeater) socket structure.
\n
"
,
current
->
comm
);
current
->
comm
);
...
@@ -1084,8 +1037,17 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
...
@@ -1084,8 +1037,17 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
return
-
EINVAL
;
return
-
EINVAL
;
call
=
ax25_findbyuid
(
current
->
euid
);
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
;
return
-
EACCES
;
}
lock_sock
(
sk
);
ax25
=
ax25_sk
(
sk
);
if
(
sk
->
zapped
==
0
)
{
err
=
-
EINVAL
;
goto
out
;
}
if
(
call
==
NULL
)
if
(
call
==
NULL
)
ax25
->
source_addr
=
addr
->
fsa_ax25
.
sax25_call
;
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)
...
@@ -1095,17 +1057,20 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
/*
/*
* User already set interface with SO_BINDTODEVICE
* User already set interface with SO_BINDTODEVICE
*/
*/
if
(
ax25
->
ax25_dev
!=
NULL
)
if
(
ax25
->
ax25_dev
!=
NULL
)
goto
done
;
goto
done
;
if
(
addr_len
>
sizeof
(
struct
sockaddr_ax25
)
&&
addr
->
fsa_ax25
.
sax25_ndigis
==
1
)
{
if
(
addr_len
>
sizeof
(
struct
sockaddr_ax25
)
&&
addr
->
fsa_ax25
.
sax25_ndigis
==
1
)
{
if
(
ax25cmp
(
&
addr
->
fsa_digipeater
[
0
],
&
null_ax25_address
)
!=
0
&&
if
(
ax25cmp
(
&
addr
->
fsa_digipeater
[
0
],
&
null_ax25_address
)
!=
0
&&
(
ax25_dev
=
ax25_addr_ax25dev
(
&
addr
->
fsa_digipeater
[
0
]))
==
NULL
)
(
ax25_dev
=
ax25_addr_ax25dev
(
&
addr
->
fsa_digipeater
[
0
]))
==
NULL
)
{
return
-
EADDRNOTAVAIL
;
err
=
-
EADDRNOTAVAIL
;
}
else
{
goto
out
;
if
((
ax25_dev
=
ax25_addr_ax25dev
(
&
addr
->
fsa_ax25
.
sax25_call
))
==
NULL
)
}
return
-
EADDRNOTAVAIL
;
}
else
{
if
((
ax25_dev
=
ax25_addr_ax25dev
(
&
addr
->
fsa_ax25
.
sax25_call
))
==
NULL
)
{
err
=
-
EADDRNOTAVAIL
;
goto
out
;
}
}
}
if
(
ax25_dev
!=
NULL
)
if
(
ax25_dev
!=
NULL
)
...
@@ -1114,41 +1079,24 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
...
@@ -1114,41 +1079,24 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
done:
done:
ax25_insert_socket
(
ax25
);
ax25_insert_socket
(
ax25
);
sk
->
zapped
=
0
;
sk
->
zapped
=
0
;
out:
release_sock
(
sk
);
return
0
;
return
0
;
}
}
/*
/*
* FIXME: nonblock behaviour looks like it may have a bug.
* 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
;
struct
sock
*
sk
=
sock
->
sk
;
ax25_cb
*
ax25
=
ax25_sk
(
sk
);
ax25_cb
*
ax25
=
ax25_sk
(
sk
);
struct
full_sockaddr_ax25
*
fsa
=
(
struct
full_sockaddr_ax25
*
)
uaddr
;
struct
full_sockaddr_ax25
*
fsa
=
(
struct
full_sockaddr_ax25
*
)
uaddr
;
ax25_digi
*
digi
=
NULL
;
ax25_digi
*
digi
=
NULL
;
int
ct
=
0
,
err
;
int
ct
=
0
,
err
=
0
;
/* 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
;
/*
/*
* some sanity checks. code further down depends on this
* 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
...
@@ -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
))
{
else
if
(
addr_len
!=
sizeof
(
struct
full_sockaddr_ax25
))
{
/* support for old structure may go away some time */
/* support for old structure may go away some time */
if
((
addr_len
<
sizeof
(
struct
sockaddr_ax25
)
+
sizeof
(
ax25_address
)
*
6
)
||
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
;
return
-
EINVAL
;
}
printk
(
KERN_WARNING
"ax25_connect(): %s uses old (6 digipeater) socket structure.
\n
"
,
printk
(
KERN_WARNING
"ax25_connect(): %s uses old (6 digipeater) socket structure.
\n
"
,
current
->
comm
);
current
->
comm
);
...
@@ -1172,21 +1121,54 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
...
@@ -1172,21 +1121,54 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
if
(
fsa
->
fsa_ax25
.
sax25_family
!=
AF_AX25
)
if
(
fsa
->
fsa_ax25
.
sax25_family
!=
AF_AX25
)
return
-
EINVAL
;
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
)
{
if
(
ax25
->
digipeat
!=
NULL
)
{
kfree
(
ax25
->
digipeat
);
kfree
(
ax25
->
digipeat
);
ax25
->
digipeat
=
NULL
;
ax25
->
digipeat
=
NULL
;
}
}
/*
/*
* Handle digi-peaters to be used.
* 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 ? */
/* Valid number of digipeaters ? */
if
(
fsa
->
fsa_ax25
.
sax25_ndigis
<
1
||
fsa
->
fsa_ax25
.
sax25_ndigis
>
AX25_MAX_DIGIS
)
if
(
fsa
->
fsa_ax25
.
sax25_ndigis
<
1
||
fsa
->
fsa_ax25
.
sax25_ndigis
>
AX25_MAX_DIGIS
)
{
return
-
EINVAL
;
err
=
-
EINVAL
;
goto
out
;
}
if
((
digi
=
kmalloc
(
sizeof
(
ax25_digi
),
GFP_KERNEL
))
==
NULL
)
if
((
digi
=
kmalloc
(
sizeof
(
ax25_digi
),
GFP_KERNEL
))
==
NULL
)
{
return
-
ENOBUFS
;
err
=
-
ENOBUFS
;
goto
out
;
}
digi
->
ndigi
=
fsa
->
fsa_ax25
.
sax25_ndigis
;
digi
->
ndigi
=
fsa
->
fsa_ax25
.
sax25_ndigis
;
digi
->
lastrepeat
=
-
1
;
digi
->
lastrepeat
=
-
1
;
...
@@ -1214,19 +1196,24 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
...
@@ -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
"
,
printk
(
KERN_WARNING
"ax25_connect(): %s uses autobind, please contact jreuter@yaina.de
\n
"
,
current
->
comm
);
current
->
comm
);
if
((
err
=
ax25_rt_autobind
(
ax25
,
&
fsa
->
fsa_ax25
.
sax25_call
))
<
0
)
if
((
err
=
ax25_rt_autobind
(
ax25
,
&
fsa
->
fsa_ax25
.
sax25_call
))
<
0
)
return
err
;
goto
out
;
ax25_fillin_cb
(
ax25
,
ax25
->
ax25_dev
);
ax25_fillin_cb
(
ax25
,
ax25
->
ax25_dev
);
ax25_insert_socket
(
ax25
);
ax25_insert_socket
(
ax25
);
}
else
{
}
else
{
if
(
ax25
->
ax25_dev
==
NULL
)
if
(
ax25
->
ax25_dev
==
NULL
)
{
return
-
EHOSTUNREACH
;
err
=
-
EHOSTUNREACH
;
goto
out
;
}
}
}
if
(
sk
->
type
==
SOCK_SEQPACKET
&&
if
(
sk
->
type
==
SOCK_SEQPACKET
&&
ax25_find_cb
(
&
ax25
->
source_addr
,
&
fsa
->
fsa_ax25
.
sax25_call
,
digi
,
ax25_find_cb
(
&
ax25
->
source_addr
,
&
fsa
->
fsa_ax25
.
sax25_call
,
digi
,
ax25
->
ax25_dev
->
dev
))
{
ax25
->
ax25_dev
->
dev
))
{
if
(
digi
!=
NULL
)
kfree
(
digi
);
if
(
digi
!=
NULL
)
return
-
EADDRINUSE
;
/* Already such a connection */
kfree
(
digi
);
err
=
-
EADDRINUSE
;
/* Already such a connection */
goto
out
;
}
}
ax25
->
dest_addr
=
fsa
->
fsa_ax25
.
sax25_call
;
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
...
@@ -1236,7 +1223,7 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
if
(
sk
->
type
!=
SOCK_SEQPACKET
)
{
if
(
sk
->
type
!=
SOCK_SEQPACKET
)
{
sock
->
state
=
SS_CONNECTED
;
sock
->
state
=
SS_CONNECTED
;
sk
->
state
=
TCP_ESTABLISHED
;
sk
->
state
=
TCP_ESTABLISHED
;
return
0
;
goto
out
;
}
}
/* Move to connecting socket, ax.25 lapb WAIT_UA.. */
/* Move to connecting socket, ax.25 lapb WAIT_UA.. */
...
@@ -1244,21 +1231,20 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
...
@@ -1244,21 +1231,20 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
sk
->
state
=
TCP_SYN_SENT
;
sk
->
state
=
TCP_SYN_SENT
;
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
ax25_std_establish_data_link
(
ax25
);
ax25_std_establish_data_link
(
ax25
);
break
;
break
;
#ifdef CONFIG_AX25_DAMA_SLAVE
#ifdef CONFIG_AX25_DAMA_SLAVE
case
AX25_PROTO_DAMA_SLAVE
:
case
AX25_PROTO_DAMA_SLAVE
:
ax25
->
modulus
=
AX25_MODULUS
;
ax25
->
modulus
=
AX25_MODULUS
;
ax25
->
window
=
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_WINDOW
];
ax25
->
ax25_dev
->
values
[
AX25_VALUES_WINDOW
];
if
(
ax25
->
ax25_dev
->
dama
.
slave
)
if
(
ax25
->
ax25_dev
->
dama
.
slave
)
ax25_ds_establish_data_link
(
ax25
);
ax25_ds_establish_data_link
(
ax25
);
else
else
ax25_std_establish_data_link
(
ax25
);
ax25_std_establish_data_link
(
ax25
);
break
;
break
;
#endif
#endif
}
}
...
@@ -1267,30 +1253,43 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
...
@@ -1267,30 +1253,43 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
ax25_start_heartbeat
(
ax25
);
ax25_start_heartbeat
(
ax25
);
/* Now the loop */
/* Now the loop */
if
(
sk
->
state
!=
TCP_ESTABLISHED
&&
(
flags
&
O_NONBLOCK
))
if
(
sk
->
state
!=
TCP_ESTABLISHED
&&
(
flags
&
O_NONBLOCK
))
{
return
-
EINPROGRESS
;
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 */
add_wait_queue
(
sk
->
sleep
,
&
wait
);
while
(
sk
->
state
==
TCP_SYN_SENT
)
{
for
(;;)
{
interruptible_sleep_on
(
sk
->
sleep
);
if
(
sk
->
state
!=
TCP_SYN_SENT
)
if
(
signal_pending
(
current
))
{
break
;
sti
();
set_current_state
(
TASK_INTERRUPTIBLE
);
release_sock
(
sk
);
if
(
!
signal_pending
(
tsk
))
{
schedule
();
lock_sock
(
sk
);
continue
;
}
return
-
ERESTARTSYS
;
return
-
ERESTARTSYS
;
}
}
current
->
state
=
TASK_RUNNING
;
remove_wait_queue
(
sk
->
sleep
,
&
wait
);
}
}
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
{
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
{
/* Not in ABM, not in WAIT_UA -> failed */
/* Not in ABM, not in WAIT_UA -> failed */
sti
();
sock
->
state
=
SS_UNCONNECTED
;
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
;
sock
->
state
=
SS_CONNECTED
;
sti
();
out:
release_sock
(
sk
);
return
0
;
return
0
;
}
}
...
@@ -1298,9 +1297,12 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
...
@@ -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
)
static
int
ax25_accept
(
struct
socket
*
sock
,
struct
socket
*
newsock
,
int
flags
)
{
{
struct
sock
*
sk
;
struct
task_struct
*
tsk
=
current
;
struct
sock
*
newsk
;
DECLARE_WAITQUEUE
(
wait
,
tsk
)
;
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
struct
sock
*
newsk
;
struct
sock
*
sk
;
int
err
=
0
;
if
(
sock
->
state
!=
SS_UNCONNECTED
)
if
(
sock
->
state
!=
SS_UNCONNECTED
)
return
-
EINVAL
;
return
-
EINVAL
;
...
@@ -1308,26 +1310,40 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
...
@@ -1308,26 +1310,40 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
if
((
sk
=
sock
->
sk
)
==
NULL
)
if
((
sk
=
sock
->
sk
)
==
NULL
)
return
-
EINVAL
;
return
-
EINVAL
;
if
(
sk
->
type
!=
SOCK_SEQPACKET
)
lock_sock
(
sk
);
return
-
EOPNOTSUPP
;
if
(
sk
->
type
!=
SOCK_SEQPACKET
)
{
err
=
-
EOPNOTSUPP
;
goto
out
;
}
if
(
sk
->
state
!=
TCP_LISTEN
)
if
(
sk
->
state
!=
TCP_LISTEN
)
{
return
-
EINVAL
;
err
=
-
EINVAL
;
goto
out
;
}
/*
/*
* The read queue this time is holding sockets ready to use
* The read queue this time is holding sockets ready to use
* hooked into the SABM we saved
* hooked into the SABM we saved
*/
*/
do
{
add_wait_queue
(
sk
->
sleep
,
&
wait
);
if
((
skb
=
skb_dequeue
(
&
sk
->
receive_queue
))
==
NULL
)
{
for
(;;)
{
if
(
flags
&
O_NONBLOCK
)
skb
=
skb_dequeue
(
&
sk
->
receive_queue
);
return
-
EWOULDBLOCK
;
if
(
skb
)
break
;
interruptible_sleep_on
(
sk
->
sleep
);
if
(
signal_pending
(
current
))
current
->
state
=
TASK_INTERRUPTIBLE
;
return
-
ERESTARTSYS
;
release_sock
(
sk
);
if
(
flags
&
O_NONBLOCK
)
return
-
EWOULDBLOCK
;
if
(
!
signal_pending
(
tsk
))
{
schedule
();
lock_sock
(
sk
);
continue
;
}
}
}
while
(
skb
==
NULL
);
return
-
ERESTARTSYS
;
}
current
->
state
=
TASK_RUNNING
;
remove_wait_queue
(
sk
->
sleep
,
&
wait
);
newsk
=
skb
->
sk
;
newsk
=
skb
->
sk
;
newsk
->
pair
=
NULL
;
newsk
->
pair
=
NULL
;
...
@@ -1340,19 +1356,29 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
...
@@ -1340,19 +1356,29 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
newsock
->
sk
=
newsk
;
newsock
->
sk
=
newsk
;
newsock
->
state
=
SS_CONNECTED
;
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
full_sockaddr_ax25
*
fsa
=
(
struct
full_sockaddr_ax25
*
)
uaddr
;
struct
sock
*
sk
=
sock
->
sk
;
unsigned
char
ndigi
,
i
;
unsigned
char
ndigi
,
i
;
ax25_cb
*
ax25
;
int
err
=
0
;
lock_sock
(
sk
);
ax25
=
ax25_sk
(
sk
);
if
(
peer
!=
0
)
{
if
(
peer
!=
0
)
{
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
{
return
-
ENOTCONN
;
err
=
-
ENOTCONN
;
goto
out
;
}
fsa
->
fsa_ax25
.
sax25_family
=
AF_AX25
;
fsa
->
fsa_ax25
.
sax25_family
=
AF_AX25
;
fsa
->
fsa_ax25
.
sax25_call
=
ax25
->
dest_addr
;
fsa
->
fsa_ax25
.
sax25_call
=
ax25
->
dest_addr
;
...
@@ -1377,41 +1403,53 @@ static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_
...
@@ -1377,41 +1403,53 @@ static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_
}
}
}
}
*
uaddr_len
=
sizeof
(
struct
full_sockaddr_ax25
);
*
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
;
struct
sockaddr_ax25
*
usax
=
(
struct
sockaddr_ax25
*
)
msg
->
msg_name
;
int
err
;
struct
sock
*
sk
=
sock
->
sk
;
struct
sockaddr_ax25
sax
;
struct
sockaddr_ax25
sax
;
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
ax25_digi
dtmp
,
*
dp
;
unsigned
char
*
asmptr
;
unsigned
char
*
asmptr
;
int
size
;
ax25_cb
*
ax25
;
ax25_digi
*
dp
;
int
lv
,
size
,
err
,
addr_len
=
msg
->
msg_namelen
;
ax25_digi
dtmp
;
int
lv
;
int
addr_len
=
msg
->
msg_namelen
;
if
(
msg
->
msg_flags
&
~
(
MSG_DONTWAIT
|
MSG_EOR
))
if
(
msg
->
msg_flags
&
~
(
MSG_DONTWAIT
|
MSG_EOR
))
{
return
-
EINVAL
;
return
-
EINVAL
;
}
lock_sock
(
sk
);
ax25
=
ax25_sk
(
sk
);
if
(
sk
->
zapped
)
if
(
sk
->
zapped
)
{
return
-
EADDRNOTAVAIL
;
err
=
-
EADDRNOTAVAIL
;
goto
out
;
}
if
(
sk
->
shutdown
&
SEND_SHUTDOWN
)
{
if
(
sk
->
shutdown
&
SEND_SHUTDOWN
)
{
send_sig
(
SIGPIPE
,
current
,
0
);
send_sig
(
SIGPIPE
,
current
,
0
);
return
-
EPIPE
;
err
=
-
EPIPE
;
goto
out
;
}
}
if
(
ax25
->
ax25_dev
==
NULL
)
if
(
ax25
->
ax25_dev
==
NULL
)
{
return
-
ENETUNREACH
;
err
=
-
ENETUNREACH
;
goto
out
;
}
if
(
usax
!=
NULL
)
{
if
(
usax
!=
NULL
)
{
if
(
usax
->
sax25_family
!=
AF_AX25
)
if
(
usax
->
sax25_family
!=
AF_AX25
)
{
return
-
EINVAL
;
err
=
-
EINVAL
;
goto
out
;
}
if
(
addr_len
==
sizeof
(
struct
sockaddr_ax25
))
{
if
(
addr_len
==
sizeof
(
struct
sockaddr_ax25
))
{
printk
(
KERN_WARNING
"ax25_sendmsg(): %s uses obsolete socket structure
\n
"
,
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
...
@@ -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
))
{
else
if
(
addr_len
!=
sizeof
(
struct
full_sockaddr_ax25
))
{
/* support for old structure may go away some time */
/* support for old structure may go away some time */
if
((
addr_len
<
sizeof
(
struct
sockaddr_ax25
)
+
sizeof
(
ax25_address
)
*
6
)
||
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
;
err
=
-
EINVAL
;
goto
out
;
}
printk
(
KERN_WARNING
"ax25_sendmsg(): %s uses old (6 digipeater) socket structure.
\n
"
,
printk
(
KERN_WARNING
"ax25_sendmsg(): %s uses old (6 digipeater) socket structure.
\n
"
,
current
->
comm
);
current
->
comm
);
...
@@ -1432,8 +1472,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
...
@@ -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
;
struct
full_sockaddr_ax25
*
fsa
=
(
struct
full_sockaddr_ax25
*
)
usax
;
/* Valid number of digipeaters ? */
/* Valid number of digipeaters ? */
if
(
usax
->
sax25_ndigis
<
1
||
usax
->
sax25_ndigis
>
AX25_MAX_DIGIS
)
if
(
usax
->
sax25_ndigis
<
1
||
usax
->
sax25_ndigis
>
AX25_MAX_DIGIS
)
{
return
-
EINVAL
;
err
=
-
EINVAL
;
goto
out
;
}
dtmp
.
ndigi
=
usax
->
sax25_ndigis
;
dtmp
.
ndigi
=
usax
->
sax25_ndigis
;
...
@@ -1447,8 +1489,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
...
@@ -1447,8 +1489,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
}
}
sax
=
*
usax
;
sax
=
*
usax
;
if
(
sk
->
type
==
SOCK_SEQPACKET
&&
ax25cmp
(
&
ax25
->
dest_addr
,
&
sax
.
sax25_call
)
!=
0
)
if
(
sk
->
type
==
SOCK_SEQPACKET
&&
ax25cmp
(
&
ax25
->
dest_addr
,
&
sax
.
sax25_call
)
!=
0
)
{
return
-
EISCONN
;
err
=
-
EISCONN
;
goto
out
;
}
if
(
usax
->
sax25_ndigis
==
0
)
if
(
usax
->
sax25_ndigis
==
0
)
dp
=
NULL
;
dp
=
NULL
;
else
else
...
@@ -1459,8 +1503,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
...
@@ -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
* it has become closed (not started closed) and is VC
* we ought to SIGPIPE, EPIPE
* we ought to SIGPIPE, EPIPE
*/
*/
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
{
return
-
ENOTCONN
;
err
=
-
ENOTCONN
;
goto
out
;
}
sax
.
sax25_family
=
AF_AX25
;
sax
.
sax25_family
=
AF_AX25
;
sax
.
sax25_call
=
ax25
->
dest_addr
;
sax
.
sax25_call
=
ax25
->
dest_addr
;
dp
=
ax25
->
digipeat
;
dp
=
ax25
->
digipeat
;
...
@@ -1474,8 +1520,9 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
...
@@ -1474,8 +1520,9 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
/* Assume the worst case */
/* Assume the worst case */
size
=
len
+
3
+
ax25_addr_size
(
dp
)
+
AX25_BPQ_HEADER_LEN
;
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
)
skb
=
sock_alloc_send_skb
(
sk
,
size
,
msg
->
msg_flags
&
MSG_DONTWAIT
,
&
err
);
return
err
;
if
(
skb
==
NULL
)
goto
out
;
skb_reserve
(
skb
,
size
-
len
);
skb_reserve
(
skb
,
size
-
len
);
...
@@ -1497,60 +1544,73 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
...
@@ -1497,60 +1544,73 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
/* Connected mode sockets go via the LAPB machine */
/* Connected mode sockets go via the LAPB machine */
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
{
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
{
kfree_skb
(
skb
);
kfree_skb
(
skb
);
return
-
ENOTCONN
;
err
=
-
ENOTCONN
;
goto
out
;
}
}
/* Shove it onto the queue and kick */
/* Shove it onto the queue and kick */
ax25_output
(
ax25
,
ax25
->
paclen
,
skb
);
ax25_output
(
ax25
,
ax25
->
paclen
,
skb
);
return
len
;
err
=
len
;
}
else
{
goto
out
;
asmptr
=
skb_push
(
skb
,
1
+
ax25_addr_size
(
dp
));
}
SOCK_DEBUG
(
sk
,
"Building AX.25 Header (dp=%p).
\n
"
,
dp
);
asmptr
=
skb_push
(
skb
,
1
+
ax25_addr_size
(
dp
)
);
if
(
dp
!=
NULL
)
SOCK_DEBUG
(
sk
,
"Building AX.25 Header (dp=%p).
\n
"
,
dp
);
SOCK_DEBUG
(
sk
,
"Num digipeaters=%d
\n
"
,
dp
->
ndigi
);
/* Build an AX.25 header */
if
(
dp
!=
NULL
)
asmptr
+=
(
lv
=
ax25_addr_build
(
asmptr
,
&
ax25
->
source_addr
,
SOCK_DEBUG
(
sk
,
"Num digipeaters=%d
\n
"
,
dp
->
ndigi
);
&
sax
.
sax25_call
,
dp
,
AX25_COMMAND
,
AX25_MODULUS
));
SOCK_DEBUG
(
sk
,
"Built header (%d bytes)
\n
"
,
lv
);
/* Build an AX.25 header */
asmptr
+=
(
lv
=
ax25_addr_build
(
asmptr
,
&
ax25
->
source_addr
,
&
sax
.
sax25_call
,
dp
,
AX25_COMMAND
,
AX25_MODULUS
));
skb
->
h
.
raw
=
asmptr
;
SOCK_DEBUG
(
sk
,
"Built header (%d bytes)
\n
"
,
lv
)
;
SOCK_DEBUG
(
sk
,
"base=%p pos=%p
\n
"
,
skb
->
data
,
asmptr
)
;
skb
->
h
.
raw
=
asmptr
;
*
asmptr
=
AX25_UI
;
SOCK_DEBUG
(
sk
,
"base=%p pos=%p
\n
"
,
skb
->
data
,
asmptr
)
;
/* Datagram frames go straight out of the door as UI */
*
asmptr
=
AX25_UI
;
skb
->
dev
=
ax25
->
ax25_dev
->
dev
;
ax25_queue_xmit
(
skb
);
/* Datagram frames go straight out of the door as UI */
skb
->
dev
=
ax25
->
ax25_dev
->
dev
;
return
len
;
ax25_queue_xmit
(
skb
);
}
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
;
struct
sock
*
sk
=
sock
->
sk
;
int
copied
;
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
int
er
;
int
copied
;
int
err
=
0
;
lock_sock
(
sk
);
/*
/*
* This works for seqpacket too. The receiver has ordered the
* This works for seqpacket too. The receiver has ordered the
* queue for us! We do one quick check first though
* queue for us! We do one quick check first though
*/
*/
if
(
sk
->
type
==
SOCK_SEQPACKET
&&
sk
->
state
!=
TCP_ESTABLISHED
)
if
(
sk
->
type
==
SOCK_SEQPACKET
&&
sk
->
state
!=
TCP_ESTABLISHED
)
{
return
-
ENOTCONN
;
err
=
-
ENOTCONN
;
goto
out
;
}
/* Now we can treat all alike */
/* Now we can treat all alike */
if
((
skb
=
skb_recv_datagram
(
sk
,
flags
&
~
MSG_DONTWAIT
,
flags
&
MSG_DONTWAIT
,
&
er
))
==
NULL
)
skb
=
skb_recv_datagram
(
sk
,
flags
&
~
MSG_DONTWAIT
,
return
er
;
flags
&
MSG_DONTWAIT
,
&
err
);
if
(
skb
==
NULL
)
goto
out
;
if
(
!
ax25_sk
(
sk
)
->
pidincl
)
if
(
!
ax25_sk
(
sk
)
->
pidincl
)
skb_pull
(
skb
,
1
);
/* Remove PID */
skb_pull
(
skb
,
1
);
/* Remove PID */
...
@@ -1561,7 +1621,7 @@ static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int f
...
@@ -1561,7 +1621,7 @@ static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int f
if
(
copied
>
size
)
{
if
(
copied
>
size
)
{
copied
=
size
;
copied
=
size
;
msg
->
msg_flags
|=
MSG_TRUNC
;
msg
->
msg_flags
|=
MSG_TRUNC
;
}
}
skb_copy_datagram_iovec
(
skb
,
0
,
msg
->
msg_iov
,
copied
);
skb_copy_datagram_iovec
(
skb
,
0
,
msg
->
msg_iov
,
copied
);
...
@@ -1590,8 +1650,12 @@ static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int f
...
@@ -1590,8 +1650,12 @@ static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int f
}
}
skb_free_datagram
(
sk
,
skb
);
skb_free_datagram
(
sk
,
skb
);
err
=
copied
;
return
copied
;
out:
release_sock
(
sk
);
return
err
;
}
}
static
int
ax25_shutdown
(
struct
socket
*
sk
,
int
how
)
static
int
ax25_shutdown
(
struct
socket
*
sk
,
int
how
)
...
@@ -1603,137 +1667,173 @@ static int ax25_shutdown(struct socket *sk, int how)
...
@@ -1603,137 +1667,173 @@ static int ax25_shutdown(struct socket *sk, int how)
static
int
ax25_ioctl
(
struct
socket
*
sock
,
unsigned
int
cmd
,
unsigned
long
arg
)
static
int
ax25_ioctl
(
struct
socket
*
sock
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
{
struct
sock
*
sk
=
sock
->
sk
;
struct
sock
*
sk
=
sock
->
sk
;
int
res
=
0
;
lock_sock
(
sk
);
switch
(
cmd
)
{
switch
(
cmd
)
{
case
TIOCOUTQ
:
{
case
TIOCOUTQ
:
{
long
amount
;
long
amount
;
amount
=
sk
->
sndbuf
-
atomic_read
(
&
sk
->
wmem_alloc
);
amount
=
sk
->
sndbuf
-
atomic_read
(
&
sk
->
wmem_alloc
);
if
(
amount
<
0
)
if
(
amount
<
0
)
amount
=
0
;
amount
=
0
;
return
put_user
(
amount
,
(
int
*
)
arg
);
res
=
put_user
(
amount
,
(
int
*
)
arg
);
}
break
;
}
case
TIOCINQ
:
{
case
TIOCINQ
:
{
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
long
amount
=
0L
;
long
amount
=
0L
;
/* These two are safe on a single CPU system as only user tasks fiddle here */
/* These two are safe on a single CPU system as only user tasks fiddle here */
if
((
skb
=
skb_peek
(
&
sk
->
receive_queue
))
!=
NULL
)
if
((
skb
=
skb_peek
(
&
sk
->
receive_queue
))
!=
NULL
)
amount
=
skb
->
len
;
amount
=
skb
->
len
;
return
put_user
(
amount
,
(
int
*
)
arg
);
res
=
put_user
(
amount
,
(
int
*
)
arg
);
}
break
;
}
case
SIOCGSTAMP
:
case
SIOCGSTAMP
:
if
(
sk
!=
NULL
)
{
if
(
sk
!=
NULL
)
{
if
(
sk
->
stamp
.
tv_sec
==
0
)
if
(
sk
->
stamp
.
tv_sec
==
0
)
{
return
-
ENOENT
;
res
=
-
ENOENT
;
return
copy_to_user
((
void
*
)
arg
,
&
sk
->
stamp
,
sizeof
(
struct
timeval
))
?
-
EFAULT
:
0
;
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
)))
{
res
=
-
EFAULT
;
break
;
}
res
=
ax25_uid_ioctl
(
cmd
,
&
sax25
);
break
;
}
case
SIOCAX25ADDUID
:
/* Add a uid to the uid/call map table */
case
SIOCAX25NOUID
:
{
/* Set the default policy (default/bar) */
case
SIOCAX25DELUID
:
/* Delete a uid from the uid/call map table */
long
amount
;
case
SIOCAX25GETUID
:
{
if
(
!
capable
(
CAP_NET_ADMIN
))
{
struct
sockaddr_ax25
sax25
;
res
=
-
EPERM
;
if
(
copy_from_user
(
&
sax25
,
(
void
*
)
arg
,
sizeof
(
sax25
)))
break
;
return
-
EFAULT
;
return
ax25_uid_ioctl
(
cmd
,
&
sax25
);
}
}
if
(
get_user
(
amount
,
(
long
*
)
arg
))
{
res
=
-
EFAULT
;
break
;
}
if
(
amount
>
AX25_NOUID_BLOCK
)
{
res
=
-
EINVAL
;
break
;
}
ax25_uid_policy
=
amount
;
res
=
0
;
break
;
}
case
SIOCAX25NOUID
:
{
/* Set the default policy (default/bar) */
case
SIOCADDRT
:
long
amount
;
case
SIOCDELRT
:
if
(
!
capable
(
CAP_NET_ADMIN
))
case
SIOCAX25OPTRT
:
return
-
EPERM
;
if
(
!
capable
(
CAP_NET_ADMIN
))
{
if
(
get_user
(
amount
,
(
long
*
)
arg
))
res
=
-
EPERM
;
return
-
EFAULT
;
break
;
if
(
amount
>
AX25_NOUID_BLOCK
)
return
-
EINVAL
;
ax25_uid_policy
=
amount
;
return
0
;
}
}
res
=
ax25_rt_ioctl
(
cmd
,
(
void
*
)
arg
);
break
;
case
SIOCADDRT
:
case
SIOCAX25CTLCON
:
case
SIOCDELRT
:
if
(
!
capable
(
CAP_NET_ADMIN
))
{
case
SIOCAX25OPTRT
:
res
=
-
EPERM
;
if
(
!
capable
(
CAP_NET_ADMIN
))
break
;
return
-
EPERM
;
return
ax25_rt_ioctl
(
cmd
,
(
void
*
)
arg
);
case
SIOCAX25CTLCON
:
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
return
ax25_ctl_ioctl
(
cmd
,
(
void
*
)
arg
);
case
SIOCAX25GETINFO
:
case
SIOCAX25GETINFOOLD
:
{
ax25_cb
*
ax25
=
ax25_sk
(
sk
);
struct
ax25_info_struct
ax25_info
;
ax25_info
.
t1
=
ax25
->
t1
/
HZ
;
ax25_info
.
t2
=
ax25
->
t2
/
HZ
;
ax25_info
.
t3
=
ax25
->
t3
/
HZ
;
ax25_info
.
idle
=
ax25
->
idle
/
(
60
*
HZ
);
ax25_info
.
n2
=
ax25
->
n2
;
ax25_info
.
t1timer
=
ax25_display_timer
(
&
ax25
->
t1timer
)
/
HZ
;
ax25_info
.
t2timer
=
ax25_display_timer
(
&
ax25
->
t2timer
)
/
HZ
;
ax25_info
.
t3timer
=
ax25_display_timer
(
&
ax25
->
t3timer
)
/
HZ
;
ax25_info
.
idletimer
=
ax25_display_timer
(
&
ax25
->
idletimer
)
/
(
60
*
HZ
);
ax25_info
.
n2count
=
ax25
->
n2count
;
ax25_info
.
state
=
ax25
->
state
;
ax25_info
.
rcv_q
=
atomic_read
(
&
sk
->
rmem_alloc
);
ax25_info
.
snd_q
=
atomic_read
(
&
sk
->
wmem_alloc
);
ax25_info
.
vs
=
ax25
->
vs
;
ax25_info
.
vr
=
ax25
->
vr
;
ax25_info
.
va
=
ax25
->
va
;
ax25_info
.
vs_max
=
ax25
->
vs
;
/* reserved */
ax25_info
.
paclen
=
ax25
->
paclen
;
ax25_info
.
window
=
ax25
->
window
;
/* old structure? */
if
(
cmd
==
SIOCAX25GETINFOOLD
)
{
static
int
warned
=
0
;
if
(
!
warned
)
{
printk
(
KERN_INFO
"%s uses old SIOCAX25GETINFO
\n
"
,
current
->
comm
);
warned
=
1
;
}
if
(
copy_to_user
((
void
*
)
arg
,
&
ax25_info
,
sizeof
(
struct
ax25_info_struct_depreciated
)))
return
-
EFAULT
;
}
else
{
if
(
copy_to_user
((
void
*
)
arg
,
&
ax25_info
,
sizeof
(
struct
ax25_info_struct
)))
return
-
EINVAL
;
}
return
0
;
}
}
res
=
ax25_ctl_ioctl
(
cmd
,
(
void
*
)
arg
);
break
;
case
SIOCAX25GETINFO
:
case
SIOCAX25GETINFOOLD
:
{
ax25_cb
*
ax25
=
ax25_sk
(
sk
);
struct
ax25_info_struct
ax25_info
;
ax25_info
.
t1
=
ax25
->
t1
/
HZ
;
ax25_info
.
t2
=
ax25
->
t2
/
HZ
;
ax25_info
.
t3
=
ax25
->
t3
/
HZ
;
ax25_info
.
idle
=
ax25
->
idle
/
(
60
*
HZ
);
ax25_info
.
n2
=
ax25
->
n2
;
ax25_info
.
t1timer
=
ax25_display_timer
(
&
ax25
->
t1timer
)
/
HZ
;
ax25_info
.
t2timer
=
ax25_display_timer
(
&
ax25
->
t2timer
)
/
HZ
;
ax25_info
.
t3timer
=
ax25_display_timer
(
&
ax25
->
t3timer
)
/
HZ
;
ax25_info
.
idletimer
=
ax25_display_timer
(
&
ax25
->
idletimer
)
/
(
60
*
HZ
);
ax25_info
.
n2count
=
ax25
->
n2count
;
ax25_info
.
state
=
ax25
->
state
;
ax25_info
.
rcv_q
=
atomic_read
(
&
sk
->
rmem_alloc
);
ax25_info
.
snd_q
=
atomic_read
(
&
sk
->
wmem_alloc
);
ax25_info
.
vs
=
ax25
->
vs
;
ax25_info
.
vr
=
ax25
->
vr
;
ax25_info
.
va
=
ax25
->
va
;
ax25_info
.
vs_max
=
ax25
->
vs
;
/* reserved */
ax25_info
.
paclen
=
ax25
->
paclen
;
ax25_info
.
window
=
ax25
->
window
;
/* old structure? */
if
(
cmd
==
SIOCAX25GETINFOOLD
)
{
static
int
warned
=
0
;
if
(
!
warned
)
{
printk
(
KERN_INFO
"%s uses old SIOCAX25GETINFO
\n
"
,
current
->
comm
);
warned
=
1
;
}
case
SIOCAX25ADDFWD
:
if
(
copy_to_user
((
void
*
)
arg
,
&
ax25_info
,
sizeof
(
struct
ax25_info_struct_depreciated
)))
{
case
SIOCAX25DELFWD
:
{
res
=
-
EFAULT
;
struct
ax25_fwd_struct
ax25_fwd
;
break
;
if
(
!
capable
(
CAP_NET_ADMIN
))
}
return
-
EPERM
;
}
else
{
if
(
copy_from_user
(
&
ax25_fwd
,
(
void
*
)
arg
,
sizeof
(
ax25_fwd
)))
if
(
copy_to_user
((
void
*
)
arg
,
&
ax25_info
,
sizeof
(
struct
ax25_info_struct
)))
{
return
-
EFAULT
;
res
=
-
EINVAL
;
return
ax25_fwd_ioctl
(
cmd
,
&
ax25_fwd
);
break
;
}
}
}
res
=
0
;
break
;
}
case
SIOCGIFADDR
:
case
SIOCAX25ADDFWD
:
case
SIOCSIFADDR
:
case
SIOCAX25DELFWD
:
{
case
SIOCGIFDSTADDR
:
struct
ax25_fwd_struct
ax25_fwd
;
case
SIOCSIFDSTADDR
:
if
(
!
capable
(
CAP_NET_ADMIN
))
{
case
SIOCGIFBRDADDR
:
res
=
-
EPERM
;
case
SIOCSIFBRDADDR
:
break
;
case
SIOCGIFNETMASK
:
}
case
SIOCSIFNETMASK
:
if
(
copy_from_user
(
&
ax25_fwd
,
(
void
*
)
arg
,
sizeof
(
ax25_fwd
)))
{
case
SIOCGIFMETRIC
:
res
=
-
EFAULT
;
case
SIOCSIFMETRIC
:
break
;
return
-
EINVAL
;
}
res
=
ax25_fwd_ioctl
(
cmd
,
&
ax25_fwd
);
break
;
}
default:
case
SIOCGIFADDR
:
return
dev_ioctl
(
cmd
,
(
void
*
)
arg
);
case
SIOCSIFADDR
:
case
SIOCGIFDSTADDR
:
case
SIOCSIFDSTADDR
:
case
SIOCGIFBRDADDR
:
case
SIOCSIFBRDADDR
:
case
SIOCGIFNETMASK
:
case
SIOCSIFNETMASK
:
case
SIOCGIFMETRIC
:
case
SIOCSIFMETRIC
:
res
=
-
EINVAL
;
break
;
default:
res
=
dev_ioctl
(
cmd
,
(
void
*
)
arg
);
break
;
}
}
release_sock
(
sk
);
/*NOTREACHED*/
return
res
;
return
0
;
}
}
static
int
ax25_get_info
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
static
int
ax25_get_info
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
...
@@ -1744,28 +1844,28 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -1744,28 +1844,28 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length)
off_t
pos
=
0
;
off_t
pos
=
0
;
off_t
begin
=
0
;
off_t
begin
=
0
;
cli
(
);
spin_lock_bh
(
&
ax25_list_lock
);
/*
/*
* New format:
* New format:
* magic dev src_addr dest_addr,digi1,digi2,.. st vs vr va t1 t1 t2 t2 t3 t3 idle idle n2 n2 rtt window paclen Snd-Q Rcv-Q inode
* magic dev src_addr dest_addr,digi1,digi2,.. st vs vr va t1 t1 t2 t2 t3 t3 idle idle n2 n2 rtt window paclen Snd-Q Rcv-Q inode
*/
*/
for
(
ax25
=
ax25_list
;
ax25
!=
NULL
;
ax25
=
ax25
->
next
)
{
for
(
ax25
=
ax25_list
;
ax25
!=
NULL
;
ax25
=
ax25
->
next
)
{
len
+=
sprintf
(
buffer
+
len
,
"%8.8lx %s %s%s "
,
len
+=
sprintf
(
buffer
+
len
,
"%8.8lx %s %s%s "
,
(
long
)
ax25
,
(
long
)
ax25
,
ax25
->
ax25_dev
==
NULL
?
"???"
:
ax25
->
ax25_dev
->
dev
->
name
,
ax25
->
ax25_dev
==
NULL
?
"???"
:
ax25
->
ax25_dev
->
dev
->
name
,
ax2asc
(
&
ax25
->
source_addr
),
ax2asc
(
&
ax25
->
source_addr
),
ax25
->
iamdigi
?
"*"
:
""
);
ax25
->
iamdigi
?
"*"
:
""
);
len
+=
sprintf
(
buffer
+
len
,
"%s"
,
ax2asc
(
&
ax25
->
dest_addr
));
len
+=
sprintf
(
buffer
+
len
,
"%s"
,
ax2asc
(
&
ax25
->
dest_addr
));
for
(
k
=
0
;
(
ax25
->
digipeat
!=
NULL
)
&&
(
k
<
ax25
->
digipeat
->
ndigi
);
k
++
)
{
for
(
k
=
0
;
(
ax25
->
digipeat
!=
NULL
)
&&
(
k
<
ax25
->
digipeat
->
ndigi
);
k
++
)
{
len
+=
sprintf
(
buffer
+
len
,
",%s%s"
,
len
+=
sprintf
(
buffer
+
len
,
",%s%s"
,
ax2asc
(
&
ax25
->
digipeat
->
calls
[
k
]),
ax2asc
(
&
ax25
->
digipeat
->
calls
[
k
]),
ax25
->
digipeat
->
repeated
[
k
]
?
"*"
:
""
);
ax25
->
digipeat
->
repeated
[
k
]
?
"*"
:
""
);
}
}
len
+=
sprintf
(
buffer
+
len
,
" %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %d %d"
,
len
+=
sprintf
(
buffer
+
len
,
" %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %d %d"
,
ax25
->
state
,
ax25
->
state
,
ax25
->
vs
,
ax25
->
vr
,
ax25
->
va
,
ax25
->
vs
,
ax25
->
vr
,
ax25
->
va
,
...
@@ -1799,7 +1899,7 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -1799,7 +1899,7 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length)
break
;
break
;
}
}
s
ti
(
);
s
pin_unlock_bh
(
&
ax25_list_lock
);
*
start
=
buffer
+
(
offset
-
begin
);
*
start
=
buffer
+
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
...
@@ -1814,7 +1914,7 @@ static struct net_proto_family ax25_family_ops = {
...
@@ -1814,7 +1914,7 @@ static struct net_proto_family ax25_family_ops = {
.
create
=
ax25_create
,
.
create
=
ax25_create
,
};
};
static
struct
proto_ops
SOCKOPS_WRAPPED
(
ax25_proto_ops
)
=
{
static
struct
proto_ops
ax25_proto_ops
=
{
.
family
=
PF_AX25
,
.
family
=
PF_AX25
,
.
release
=
ax25_release
,
.
release
=
ax25_release
,
...
@@ -1835,15 +1935,14 @@ static struct proto_ops SOCKOPS_WRAPPED(ax25_proto_ops) = {
...
@@ -1835,15 +1935,14 @@ static struct proto_ops SOCKOPS_WRAPPED(ax25_proto_ops) = {
.
sendpage
=
sock_no_sendpage
,
.
sendpage
=
sock_no_sendpage
,
};
};
#include <linux/smp_lock.h>
SOCKOPS_WRAP
(
ax25_proto
,
PF_AX25
);
/*
/*
* Called by socket.c on kernel start up
* Called by socket.c on kernel start up
*/
*/
static
struct
packet_type
ax25_packet_type
=
{
static
struct
packet_type
ax25_packet_type
=
{
.
type
=
__constant_htons
(
ETH_P_AX25
),
.
type
=
__constant_htons
(
ETH_P_AX25
),
.
func
=
ax25_kiss_rcv
,
.
dev
=
NULL
,
/* All devices */
.
func
=
ax25_kiss_rcv
,
.
data
=
(
void
*
)
1
};
};
static
struct
notifier_block
ax25_dev_notifier
=
{
static
struct
notifier_block
ax25_dev_notifier
=
{
...
...
net/ax25/ax25_addr.c
View file @
b331768e
/*
/*
* 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) 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
* AX.25 036 Jonathan(G4KLX) Split from ax25_subr.c.
*/
*/
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
...
@@ -165,14 +152,14 @@ unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, a
...
@@ -165,14 +152,14 @@ unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, a
if
(
flags
!=
NULL
)
{
if
(
flags
!=
NULL
)
{
*
flags
=
0
;
*
flags
=
0
;
if
(
buf
[
6
]
&
AX25_CBIT
)
if
(
buf
[
6
]
&
AX25_CBIT
)
*
flags
=
AX25_COMMAND
;
*
flags
=
AX25_COMMAND
;
if
(
buf
[
13
]
&
AX25_CBIT
)
if
(
buf
[
13
]
&
AX25_CBIT
)
*
flags
=
AX25_RESPONSE
;
*
flags
=
AX25_RESPONSE
;
}
}
if
(
dama
!=
NULL
)
if
(
dama
!=
NULL
)
*
dama
=
~
buf
[
13
]
&
AX25_DAMA_FLAG
;
*
dama
=
~
buf
[
13
]
&
AX25_DAMA_FLAG
;
/* Copy to, from */
/* Copy to, from */
...
@@ -243,7 +230,7 @@ int ax25_addr_build(unsigned char *buf, ax25_address *src, ax25_address *dest, a
...
@@ -243,7 +230,7 @@ int ax25_addr_build(unsigned char *buf, ax25_address *src, ax25_address *dest, a
if
(
d
==
NULL
||
d
->
ndigi
==
0
)
{
if
(
d
==
NULL
||
d
->
ndigi
==
0
)
{
buf
[
6
]
|=
AX25_EBIT
;
buf
[
6
]
|=
AX25_EBIT
;
return
2
*
AX25_ADDR_LEN
;
return
2
*
AX25_ADDR_LEN
;
}
}
buf
+=
AX25_ADDR_LEN
;
buf
+=
AX25_ADDR_LEN
;
len
+=
AX25_ADDR_LEN
;
len
+=
AX25_ADDR_LEN
;
...
@@ -277,7 +264,7 @@ int ax25_addr_size(ax25_digi *dp)
...
@@ -277,7 +264,7 @@ int ax25_addr_size(ax25_digi *dp)
return
AX25_ADDR_LEN
*
(
2
+
dp
->
ndigi
);
return
AX25_ADDR_LEN
*
(
2
+
dp
->
ndigi
);
}
}
/*
/*
* Reverse Digipeat List. May not pass both parameters as same struct
* Reverse Digipeat List. May not pass both parameters as same struct
*/
*/
void
ax25_digi_invert
(
ax25_digi
*
in
,
ax25_digi
*
out
)
void
ax25_digi_invert
(
ax25_digi
*
in
,
ax25_digi
*
out
)
...
...
net/ax25/ax25_dev.c
View file @
b331768e
/*
/*
* 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) 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.
*
* 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.
*/
*/
#include <linux/config.h>
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
...
@@ -27,6 +17,7 @@
...
@@ -27,6 +17,7 @@
#include <linux/string.h>
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/net.h>
#include <linux/spinlock.h>
#include <net/ax25.h>
#include <net/ax25.h>
#include <linux/inet.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/netdevice.h>
...
@@ -41,27 +32,35 @@
...
@@ -41,27 +32,35 @@
#include <linux/init.h>
#include <linux/init.h>
ax25_dev
*
ax25_dev_list
;
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_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
)
for
(
ax25_dev
=
ax25_dev_list
;
ax25_dev
!=
NULL
;
ax25_dev
=
ax25_dev
->
next
)
if
(
ax25_dev
->
dev
==
dev
)
if
(
ax25_dev
->
dev
==
dev
)
{
return
ax25_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_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
)
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
)
if
(
ax25cmp
(
addr
,
(
ax25_address
*
)
ax25_dev
->
dev
->
dev_addr
)
==
0
)
{
return
ax25_dev
;
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)
...
@@ -71,7 +70,6 @@ ax25_dev *ax25_addr_ax25dev(ax25_address *addr)
void
ax25_dev_device_up
(
struct
net_device
*
dev
)
void
ax25_dev_device_up
(
struct
net_device
*
dev
)
{
{
ax25_dev
*
ax25_dev
;
ax25_dev
*
ax25_dev
;
unsigned
long
flags
;
if
((
ax25_dev
=
kmalloc
(
sizeof
(
*
ax25_dev
),
GFP_ATOMIC
))
==
NULL
)
{
if
((
ax25_dev
=
kmalloc
(
sizeof
(
*
ax25_dev
),
GFP_ATOMIC
))
==
NULL
)
{
printk
(
KERN_ERR
"AX.25: ax25_dev_device_up - out of memory
\n
"
);
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)
...
@@ -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_PROTOCOL
]
=
AX25_DEF_PROTOCOL
;
ax25_dev
->
values
[
AX25_VALUES_DS_TIMEOUT
]
=
AX25_DEF_DS_TIMEOUT
;
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
->
next
=
ax25_dev_list
;
ax25_dev_list
=
ax25_dev
;
ax25_dev_list
=
ax25_dev
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
ax25_dev_lock
);
ax25_register_sysctl
();
ax25_register_sysctl
();
}
}
...
@@ -111,14 +109,13 @@ void ax25_dev_device_up(struct net_device *dev)
...
@@ -111,14 +109,13 @@ void ax25_dev_device_up(struct net_device *dev)
void
ax25_dev_device_down
(
struct
net_device
*
dev
)
void
ax25_dev_device_down
(
struct
net_device
*
dev
)
{
{
ax25_dev
*
s
,
*
ax25_dev
;
ax25_dev
*
s
,
*
ax25_dev
;
unsigned
long
flags
;
if
((
ax25_dev
=
ax25_dev_ax25dev
(
dev
))
==
NULL
)
if
((
ax25_dev
=
ax25_dev_ax25dev
(
dev
))
==
NULL
)
return
;
return
;
ax25_unregister_sysctl
();
ax25_unregister_sysctl
();
s
ave_flags
(
flags
);
cli
(
);
s
pin_lock_bh
(
&
ax25_dev_lock
);
#ifdef CONFIG_AX25_DAMA_SLAVE
#ifdef CONFIG_AX25_DAMA_SLAVE
ax25_ds_del_timer
(
ax25_dev
);
ax25_ds_del_timer
(
ax25_dev
);
...
@@ -133,7 +130,7 @@ void ax25_dev_device_down(struct net_device *dev)
...
@@ -133,7 +130,7 @@ void ax25_dev_device_down(struct net_device *dev)
if
((
s
=
ax25_dev_list
)
==
ax25_dev
)
{
if
((
s
=
ax25_dev_list
)
==
ax25_dev
)
{
ax25_dev_list
=
s
->
next
;
ax25_dev_list
=
s
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
ax25_dev_lock
);
kfree
(
ax25_dev
);
kfree
(
ax25_dev
);
ax25_register_sysctl
();
ax25_register_sysctl
();
return
;
return
;
...
@@ -142,7 +139,7 @@ void ax25_dev_device_down(struct net_device *dev)
...
@@ -142,7 +139,7 @@ void ax25_dev_device_down(struct net_device *dev)
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
if
(
s
->
next
==
ax25_dev
)
{
if
(
s
->
next
==
ax25_dev
)
{
s
->
next
=
ax25_dev
->
next
;
s
->
next
=
ax25_dev
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
ax25_dev_lock
);
kfree
(
ax25_dev
);
kfree
(
ax25_dev
);
ax25_register_sysctl
();
ax25_register_sysctl
();
return
;
return
;
...
@@ -150,8 +147,8 @@ void ax25_dev_device_down(struct net_device *dev)
...
@@ -150,8 +147,8 @@ void ax25_dev_device_down(struct net_device *dev)
s
=
s
->
next
;
s
=
s
->
next
;
}
}
spin_unlock_bh
(
&
ax25_dev_lock
);
restore_flags
(
flags
);
ax25_register_sysctl
();
ax25_register_sysctl
();
}
}
...
@@ -163,22 +160,22 @@ int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd)
...
@@ -163,22 +160,22 @@ int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd)
return
-
EINVAL
;
return
-
EINVAL
;
switch
(
cmd
)
{
switch
(
cmd
)
{
case
SIOCAX25ADDFWD
:
case
SIOCAX25ADDFWD
:
if
((
fwd_dev
=
ax25_addr_ax25dev
(
&
fwd
->
port_to
))
==
NULL
)
if
((
fwd_dev
=
ax25_addr_ax25dev
(
&
fwd
->
port_to
))
==
NULL
)
return
-
EINVAL
;
return
-
EINVAL
;
if
(
ax25_dev
->
forward
!=
NULL
)
if
(
ax25_dev
->
forward
!=
NULL
)
return
-
EINVAL
;
return
-
EINVAL
;
ax25_dev
->
forward
=
fwd_dev
->
dev
;
ax25_dev
->
forward
=
fwd_dev
->
dev
;
break
;
break
;
case
SIOCAX25DELFWD
:
if
(
ax25_dev
->
forward
==
NULL
)
return
-
EINVAL
;
ax25_dev
->
forward
=
NULL
;
break
;
default:
case
SIOCAX25DELFWD
:
if
(
ax25_dev
->
forward
==
NULL
)
return
-
EINVAL
;
return
-
EINVAL
;
ax25_dev
->
forward
=
NULL
;
break
;
default:
return
-
EINVAL
;
}
}
return
0
;
return
0
;
...
@@ -202,12 +199,16 @@ struct net_device *ax25_fwd_dev(struct net_device *dev)
...
@@ -202,12 +199,16 @@ struct net_device *ax25_fwd_dev(struct net_device *dev)
*/
*/
void
__exit
ax25_dev_free
(
void
)
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
)
{
while
(
ax25_dev
!=
NULL
)
{
s
=
ax25_dev
;
s
=
ax25_dev
;
ax25_dev
=
ax25_dev
->
next
;
ax25_dev
=
ax25_dev
->
next
;
kfree
(
s
);
kfree
(
s
);
}
}
ax25_dev_list
=
NULL
;
spin_unlock_bh
(
&
ax25_dev_lock
);
}
}
net/ax25/ax25_ds_in.c
View file @
b331768e
/*
/*
* 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) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.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 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
*/
*/
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
...
@@ -53,54 +38,56 @@
...
@@ -53,54 +38,56 @@
static
int
ax25_ds_state1_machine
(
ax25_cb
*
ax25
,
struct
sk_buff
*
skb
,
int
frametype
,
int
pf
,
int
type
)
static
int
ax25_ds_state1_machine
(
ax25_cb
*
ax25
,
struct
sk_buff
*
skb
,
int
frametype
,
int
pf
,
int
type
)
{
{
switch
(
frametype
)
{
switch
(
frametype
)
{
case
AX25_SABM
:
case
AX25_SABM
:
ax25
->
modulus
=
AX25_MODULUS
;
ax25
->
modulus
=
AX25_MODULUS
;
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_WINDOW
];
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_WINDOW
];
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
break
;
break
;
case
AX25_SABME
:
case
AX25_SABME
:
ax25
->
modulus
=
AX25_EMODULUS
;
ax25
->
modulus
=
AX25_EMODULUS
;
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_EWINDOW
];
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_EWINDOW
];
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
break
;
break
;
case
AX25_DISC
:
case
AX25_DISC
:
ax25_send_control
(
ax25
,
AX25_DM
,
pf
,
AX25_RESPONSE
);
ax25_send_control
(
ax25
,
AX25_DM
,
pf
,
AX25_RESPONSE
);
break
;
break
;
case
AX25_UA
:
case
AX25_UA
:
ax25_calculate_rtt
(
ax25
);
ax25_calculate_rtt
(
ax25
);
ax25_stop_t1timer
(
ax25
);
ax25_stop_t1timer
(
ax25
);
ax25_start_t3timer
(
ax25
);
ax25_start_t3timer
(
ax25
);
ax25_start_idletimer
(
ax25
);
ax25_start_idletimer
(
ax25
);
ax25
->
vs
=
0
;
ax25
->
vs
=
0
;
ax25
->
va
=
0
;
ax25
->
va
=
0
;
ax25
->
vr
=
0
;
ax25
->
vr
=
0
;
ax25
->
state
=
AX25_STATE_3
;
ax25
->
state
=
AX25_STATE_3
;
ax25
->
n2count
=
0
;
ax25
->
n2count
=
0
;
if
(
ax25
->
sk
!=
NULL
)
{
if
(
ax25
->
sk
!=
NULL
)
{
ax25
->
sk
->
state
=
TCP_ESTABLISHED
;
ax25
->
sk
->
state
=
TCP_ESTABLISHED
;
/* For WAIT_SABM connections we will produce an accept ready socket here */
/* For WAIT_SABM connections we will produce an accept ready socket here */
if
(
!
ax25
->
sk
->
dead
)
if
(
!
ax25
->
sk
->
dead
)
ax25
->
sk
->
state_change
(
ax25
->
sk
);
ax25
->
sk
->
state_change
(
ax25
->
sk
);
}
}
ax25_dama_on
(
ax25
);
ax25_dama_on
(
ax25
);
/* according to DK4EGs spec we are required to
/* according to DK4EGs spec we are required to
* send a RR RESPONSE FINAL NR=0.
* send a RR RESPONSE FINAL NR=0.
*/
*/
ax25_std_enquiry_response
(
ax25
);
ax25_std_enquiry_response
(
ax25
);
break
;
break
;
case
AX25_DM
:
case
AX25_DM
:
if
(
pf
)
ax25_disconnect
(
ax25
,
ECONNREFUSED
);
if
(
pf
)
break
;
ax25_disconnect
(
ax25
,
ECONNREFUSED
);
break
;
default:
if
(
pf
)
ax25_send_control
(
ax25
,
AX25_SABM
,
AX25_POLLON
,
AX25_COMMAND
);
default:
break
;
if
(
pf
)
ax25_send_control
(
ax25
,
AX25_SABM
,
AX25_POLLON
,
AX25_COMMAND
);
break
;
}
}
return
0
;
return
0
;
...
@@ -114,38 +101,38 @@ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
...
@@ -114,38 +101,38 @@ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
static
int
ax25_ds_state2_machine
(
ax25_cb
*
ax25
,
struct
sk_buff
*
skb
,
int
frametype
,
int
pf
,
int
type
)
static
int
ax25_ds_state2_machine
(
ax25_cb
*
ax25
,
struct
sk_buff
*
skb
,
int
frametype
,
int
pf
,
int
type
)
{
{
switch
(
frametype
)
{
switch
(
frametype
)
{
case
AX25_SABM
:
case
AX25_SABM
:
case
AX25_SABME
:
case
AX25_SABME
:
ax25_send_control
(
ax25
,
AX25_DISC
,
AX25_POLLON
,
AX25_COMMAND
);
ax25_send_control
(
ax25
,
AX25_DISC
,
AX25_POLLON
,
AX25_COMMAND
);
ax25_dama_off
(
ax25
);
ax25_dama_off
(
ax25
);
break
;
break
;
case
AX25_DISC
:
case
AX25_DISC
:
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
ax25_dama_off
(
ax25
);
ax25_disconnect
(
ax25
,
0
);
break
;
case
AX25_DM
:
case
AX25_UA
:
if
(
pf
)
{
ax25_dama_off
(
ax25
);
ax25_dama_off
(
ax25
);
ax25_disconnect
(
ax25
,
0
);
ax25_disconnect
(
ax25
,
0
);
break
;
}
break
;
case
AX25_DM
:
case
AX25_UA
:
case
AX25_I
:
if
(
pf
)
{
case
AX25_REJ
:
ax25_dama_off
(
ax25
);
case
AX25_RNR
:
ax25_disconnect
(
ax25
,
0
);
case
AX25_RR
:
}
if
(
pf
)
{
break
;
ax25_send_control
(
ax25
,
AX25_DISC
,
AX25_POLLON
,
AX25_COMMAND
);
ax25_dama_off
(
ax25
);
case
AX25_I
:
}
case
AX25_REJ
:
break
;
case
AX25_RNR
:
case
AX25_RR
:
if
(
pf
)
{
ax25_send_control
(
ax25
,
AX25_DISC
,
AX25_POLLON
,
AX25_COMMAND
);
ax25_dama_off
(
ax25
);
}
break
;
default:
default:
break
;
break
;
}
}
return
0
;
return
0
;
...
@@ -161,127 +148,127 @@ static int ax25_ds_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
...
@@ -161,127 +148,127 @@ static int ax25_ds_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
int
queued
=
0
;
int
queued
=
0
;
switch
(
frametype
)
{
switch
(
frametype
)
{
case
AX25_SABM
:
case
AX25_SABM
:
case
AX25_SABME
:
case
AX25_SABME
:
if
(
frametype
==
AX25_SABM
)
{
if
(
frametype
==
AX25_SABM
)
{
ax25
->
modulus
=
AX25_MODULUS
;
ax25
->
modulus
=
AX25_MODULUS
;
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_WINDOW
];
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_WINDOW
];
}
else
{
}
else
{
ax25
->
modulus
=
AX25_EMODULUS
;
ax25
->
modulus
=
AX25_EMODULUS
;
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_EWINDOW
];
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_EWINDOW
];
}
}
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
ax25_stop_t1timer
(
ax25
);
ax25_stop_t1timer
(
ax25
);
ax25_start_t3timer
(
ax25
);
ax25_start_t3timer
(
ax25
);
ax25_start_idletimer
(
ax25
);
ax25_start_idletimer
(
ax25
);
ax25
->
condition
=
0x00
;
ax25
->
condition
=
0x00
;
ax25
->
vs
=
0
;
ax25
->
vs
=
0
;
ax25
->
va
=
0
;
ax25
->
va
=
0
;
ax25
->
vr
=
0
;
ax25
->
vr
=
0
;
ax25_requeue_frames
(
ax25
);
ax25_requeue_frames
(
ax25
);
ax25_dama_on
(
ax25
);
ax25_dama_on
(
ax25
);
break
;
break
;
case
AX25_DISC
:
case
AX25_DISC
:
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
ax25_dama_off
(
ax25
);
ax25_dama_off
(
ax25
);
ax25_disconnect
(
ax25
,
0
);
ax25_disconnect
(
ax25
,
0
);
break
;
break
;
case
AX25_DM
:
case
AX25_DM
:
ax25_dama_off
(
ax25
);
ax25_dama_off
(
ax25
);
ax25_disconnect
(
ax25
,
ECONNRESET
);
ax25_disconnect
(
ax25
,
ECONNRESET
);
break
;
break
;
case
AX25_RR
:
case
AX25_RNR
:
if
(
frametype
==
AX25_RR
)
ax25
->
condition
&=
~
AX25_COND_PEER_RX_BUSY
;
else
ax25
->
condition
|=
AX25_COND_PEER_RX_BUSY
;
if
(
ax25_validate_nr
(
ax25
,
nr
))
{
if
(
ax25_check_iframes_acked
(
ax25
,
nr
))
ax25
->
n2count
=
0
;
if
(
type
==
AX25_COMMAND
&&
pf
)
ax25_ds_enquiry_response
(
ax25
);
}
else
{
ax25_ds_nr_error_recovery
(
ax25
);
ax25
->
state
=
AX25_STATE_1
;
}
break
;
case
AX25_RR
:
case
AX25_REJ
:
case
AX25_RNR
:
ax25
->
condition
&=
~
AX25_COND_PEER_RX_BUSY
;
if
(
frametype
==
AX25_RR
)
ax25
->
condition
&=
~
AX25_COND_PEER_RX_BUSY
;
else
ax25
->
condition
|=
AX25_COND_PEER_RX_BUSY
;
if
(
ax25_validate_nr
(
ax25
,
nr
))
{
if
(
ax25_check_iframes_acked
(
ax25
,
nr
))
ax25
->
n2count
=
0
;
if
(
type
==
AX25_COMMAND
&&
pf
)
ax25_ds_enquiry_response
(
ax25
);
}
else
{
ax25_ds_nr_error_recovery
(
ax25
);
ax25
->
state
=
AX25_STATE_1
;
}
break
;
case
AX25_REJ
:
if
(
ax25_validate_nr
(
ax25
,
nr
))
{
ax25
->
condition
&=
~
AX25_COND_PEER_RX_BUSY
;
if
(
ax25
->
va
!=
nr
)
ax25
->
n2count
=
0
;
if
(
ax25_validate_nr
(
ax25
,
nr
))
{
ax25_frames_acked
(
ax25
,
nr
);
if
(
ax25
->
va
!=
nr
)
ax25_calculate_rtt
(
ax25
);
ax25
->
n2count
=
0
;
ax25_stop_t1timer
(
ax25
);
ax25_start_t3timer
(
ax25
);
ax25_requeue_frames
(
ax25
);
ax25_frames_acked
(
ax25
,
nr
);
if
(
type
==
AX25_COMMAND
&&
pf
)
ax25_calculate_rtt
(
ax25
);
ax25_ds_enquiry_response
(
ax25
);
ax25_stop_t1timer
(
ax25
);
}
else
{
ax25_start_t3timer
(
ax25
);
ax25_ds_nr_error_recovery
(
ax25
);
ax25_requeue_frames
(
ax25
);
ax25
->
state
=
AX25_STATE_1
;
}
break
;
if
(
type
==
AX25_COMMAND
&&
pf
)
case
AX25_I
:
ax25_ds_enquiry_response
(
ax25
);
if
(
!
ax25_validate_nr
(
ax25
,
nr
))
{
}
else
{
ax25_ds_nr_error_recovery
(
ax25
);
ax25_ds_nr_error_recovery
(
ax25
);
ax25
->
state
=
AX25_STATE_1
;
ax25
->
state
=
AX25_STATE_1
;
}
break
;
break
;
}
case
AX25_I
:
if
(
ax25
->
condition
&
AX25_COND_PEER_RX_BUSY
)
{
if
(
!
ax25_validate_nr
(
ax25
,
nr
))
{
ax25_frames_acked
(
ax25
,
nr
);
ax25_ds_nr_error_recovery
(
ax25
);
ax25
->
n2count
=
0
;
ax25
->
state
=
AX25_STATE_1
;
}
else
{
break
;
if
(
ax25_check_iframes_acked
(
ax25
,
nr
))
}
if
(
ax25
->
condition
&
AX25_COND_PEER_RX_BUSY
)
{
ax25_frames_acked
(
ax25
,
nr
);
ax25
->
n2count
=
0
;
ax25
->
n2count
=
0
;
}
if
(
ax25
->
condition
&
AX25_COND_OWN_RX_BUSY
)
{
if
(
pf
)
ax25_ds_enquiry_response
(
ax25
);
break
;
}
if
(
ns
==
ax25
->
vr
)
{
ax25
->
vr
=
(
ax25
->
vr
+
1
)
%
ax25
->
modulus
;
queued
=
ax25_rx_iframe
(
ax25
,
skb
);
if
(
ax25
->
condition
&
AX25_COND_OWN_RX_BUSY
)
ax25
->
vr
=
ns
;
/* ax25->vr - 1 */
ax25
->
condition
&=
~
AX25_COND_REJECT
;
if
(
pf
)
{
ax25_ds_enquiry_response
(
ax25
);
}
else
{
}
else
{
if
(
ax25_check_iframes_acked
(
ax25
,
nr
))
if
(
!
(
ax25
->
condition
&
AX25_COND_ACK_PENDING
))
{
ax25
->
n2count
=
0
;
ax25
->
condition
|=
AX25_COND_ACK_PENDING
;
ax25_start_t2timer
(
ax25
);
}
}
}
if
(
ax25
->
condition
&
AX25_COND_OWN_RX_BUSY
)
{
}
else
{
if
(
ax25
->
condition
&
AX25_COND_REJECT
)
{
if
(
pf
)
ax25_ds_enquiry_response
(
ax25
);
if
(
pf
)
ax25_ds_enquiry_response
(
ax25
);
break
;
}
if
(
ns
==
ax25
->
vr
)
{
ax25
->
vr
=
(
ax25
->
vr
+
1
)
%
ax25
->
modulus
;
queued
=
ax25_rx_iframe
(
ax25
,
skb
);
if
(
ax25
->
condition
&
AX25_COND_OWN_RX_BUSY
)
ax25
->
vr
=
ns
;
/* ax25->vr - 1 */
ax25
->
condition
&=
~
AX25_COND_REJECT
;
if
(
pf
)
{
ax25_ds_enquiry_response
(
ax25
);
}
else
{
if
(
!
(
ax25
->
condition
&
AX25_COND_ACK_PENDING
))
{
ax25
->
condition
|=
AX25_COND_ACK_PENDING
;
ax25_start_t2timer
(
ax25
);
}
}
}
else
{
}
else
{
if
(
ax25
->
condition
&
AX25_COND_REJECT
)
{
ax25
->
condition
|=
AX25_COND_REJECT
;
if
(
pf
)
ax25_ds_enquiry_response
(
ax25
);
ax25_ds_enquiry_response
(
ax25
);
}
else
{
ax25
->
condition
&=
~
AX25_COND_ACK_PENDING
;
ax25
->
condition
|=
AX25_COND_REJECT
;
ax25_ds_enquiry_response
(
ax25
);
ax25
->
condition
&=
~
AX25_COND_ACK_PENDING
;
}
}
}
break
;
}
break
;
case
AX25_FRMR
:
case
AX25_FRMR
:
case
AX25_ILLEGAL
:
case
AX25_ILLEGAL
:
ax25_ds_establish_data_link
(
ax25
);
ax25_ds_establish_data_link
(
ax25
);
ax25
->
state
=
AX25_STATE_1
;
ax25
->
state
=
AX25_STATE_1
;
break
;
break
;
default:
default:
break
;
break
;
}
}
return
queued
;
return
queued
;
...
@@ -297,15 +284,15 @@ int ax25_ds_frame_in(ax25_cb *ax25, struct sk_buff *skb, int type)
...
@@ -297,15 +284,15 @@ int ax25_ds_frame_in(ax25_cb *ax25, struct sk_buff *skb, int type)
frametype
=
ax25_decode
(
ax25
,
skb
,
&
ns
,
&
nr
,
&
pf
);
frametype
=
ax25_decode
(
ax25
,
skb
,
&
ns
,
&
nr
,
&
pf
);
switch
(
ax25
->
state
)
{
switch
(
ax25
->
state
)
{
case
AX25_STATE_1
:
case
AX25_STATE_1
:
queued
=
ax25_ds_state1_machine
(
ax25
,
skb
,
frametype
,
pf
,
type
);
queued
=
ax25_ds_state1_machine
(
ax25
,
skb
,
frametype
,
pf
,
type
);
break
;
break
;
case
AX25_STATE_2
:
case
AX25_STATE_2
:
queued
=
ax25_ds_state2_machine
(
ax25
,
skb
,
frametype
,
pf
,
type
);
queued
=
ax25_ds_state2_machine
(
ax25
,
skb
,
frametype
,
pf
,
type
);
break
;
break
;
case
AX25_STATE_3
:
case
AX25_STATE_3
:
queued
=
ax25_ds_state3_machine
(
ax25
,
skb
,
frametype
,
ns
,
nr
,
pf
,
type
);
queued
=
ax25_ds_state3_machine
(
ax25
,
skb
,
frametype
,
ns
,
nr
,
pf
,
type
);
break
;
break
;
}
}
return
queued
;
return
queued
;
...
...
net/ax25/ax25_ds_subr.c
View file @
b331768e
/*
/*
* 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) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.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 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.
*/
*/
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
...
@@ -31,6 +16,7 @@
...
@@ -31,6 +16,7 @@
#include <linux/timer.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/sockios.h>
#include <linux/spinlock.h>
#include <linux/net.h>
#include <linux/net.h>
#include <net/ax25.h>
#include <net/ax25.h>
#include <linux/inet.h>
#include <linux/inet.h>
...
@@ -73,7 +59,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
...
@@ -73,7 +59,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
* DL1BKE-7->DB0PRA-6 DB0ACH <I C S3 R5>
* DL1BKE-7->DB0PRA-6 DB0ACH <I C S3 R5>
*
*
* Flexnet refuses to send us *any* I frame if we send
* Flexnet refuses to send us *any* I frame if we send
* a REJ in case AX25_COND_REJECT is set. It is superfluous in
* a REJ in case AX25_COND_REJECT is set. It is superfluous in
* this mode anyway (a RR or RNR invokes the retransmission).
* this mode anyway (a RR or RNR invokes the retransmission).
* Is this a Flexnet bug?
* Is this a Flexnet bug?
*/
*/
...
@@ -93,6 +79,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
...
@@ -93,6 +79,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
ax25_start_t3timer
(
ax25
);
ax25_start_t3timer
(
ax25
);
ax25_ds_set_timer
(
ax25
->
ax25_dev
);
ax25_ds_set_timer
(
ax25
->
ax25_dev
);
spin_lock_bh
(
&
ax25_list_lock
);
for
(
ax25o
=
ax25_list
;
ax25o
!=
NULL
;
ax25o
=
ax25o
->
next
)
{
for
(
ax25o
=
ax25_list
;
ax25o
!=
NULL
;
ax25o
=
ax25o
->
next
)
{
if
(
ax25o
==
ax25
)
if
(
ax25o
==
ax25
)
continue
;
continue
;
...
@@ -118,6 +105,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
...
@@ -118,6 +105,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
if
(
ax25o
->
state
!=
AX25_STATE_0
)
if
(
ax25o
->
state
!=
AX25_STATE_0
)
ax25_start_t3timer
(
ax25o
);
ax25_start_t3timer
(
ax25o
);
}
}
spin_unlock_bh
(
&
ax25_list_lock
);
}
}
void
ax25_ds_establish_data_link
(
ax25_cb
*
ax25
)
void
ax25_ds_establish_data_link
(
ax25_cb
*
ax25
)
...
@@ -132,8 +120,8 @@ void ax25_ds_establish_data_link(ax25_cb *ax25)
...
@@ -132,8 +120,8 @@ void ax25_ds_establish_data_link(ax25_cb *ax25)
/*
/*
* :::FIXME:::
* :::FIXME:::
* This is a kludge. Not all drivers recognize kiss commands.
* This is a kludge. Not all drivers recognize kiss commands.
* We need a driver level request to switch duplex mode, that does
* We need a driver level request to switch duplex mode, that does
* either SCC changing, PI config or KISS as required. Currently
* either SCC changing, PI config or KISS as required. Currently
* this request isn't reliable.
* this request isn't reliable.
*/
*/
...
@@ -164,19 +152,24 @@ static void ax25_kiss_cmd(ax25_dev *ax25_dev, unsigned char cmd, unsigned char p
...
@@ -164,19 +152,24 @@ static void ax25_kiss_cmd(ax25_dev *ax25_dev, unsigned char cmd, unsigned char p
* A nasty problem arises if we count the number of DAMA connections
* A nasty problem arises if we count the number of DAMA connections
* wrong, especially when connections on the device already existed
* wrong, especially when connections on the device already existed
* and our network node (or the sysop) decides to turn on DAMA Master
* and our network node (or the sysop) decides to turn on DAMA Master
* mode. We thus flag the 'real' slave connections with
* mode. We thus flag the 'real' slave connections with
* ax25->dama_slave=1 and look on every disconnect if still slave
* ax25->dama_slave=1 and look on every disconnect if still slave
* connections exist.
* connections exist.
*/
*/
static
int
ax25_check_dama_slave
(
ax25_dev
*
ax25_dev
)
static
int
ax25_check_dama_slave
(
ax25_dev
*
ax25_dev
)
{
{
ax25_cb
*
ax25
;
ax25_cb
*
ax25
;
int
res
=
0
;
spin_lock_bh
(
&
ax25_list_lock
);
for
(
ax25
=
ax25_list
;
ax25
!=
NULL
;
ax25
=
ax25
->
next
)
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
)
if
(
ax25
->
ax25_dev
==
ax25_dev
&&
(
ax25
->
condition
&
AX25_COND_DAMA_MODE
)
&&
ax25
->
state
>
AX25_STATE_1
)
{
return
1
;
res
=
1
;
break
;
}
spin_unlock_bh
(
&
ax25_list_lock
);
return
0
;
return
res
;
}
}
void
ax25_dev_dama_on
(
ax25_dev
*
ax25_dev
)
void
ax25_dev_dama_on
(
ax25_dev
*
ax25_dev
)
...
...
net/ax25/ax25_ds_timer.c
View file @
b331768e
/*
/*
* 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) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.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.
*
* 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.
*/
*/
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
#include <linux/spinlock.h>
#include <linux/in.h>
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/jiffies.h>
...
@@ -41,7 +34,7 @@ static void ax25_ds_timeout(unsigned long);
...
@@ -41,7 +34,7 @@ static void ax25_ds_timeout(unsigned long);
/*
/*
* Add DAMA slave timeout timer to timer list.
* Add DAMA slave timeout timer to timer list.
* Unlike the connection based timers the timeout function gets
* Unlike the connection based timers the timeout function gets
* triggered every second. Please note that NET_AX25_DAMA_SLAVE_TIMEOUT
* triggered every second. Please note that NET_AX25_DAMA_SLAVE_TIMEOUT
* (aka /proc/sys/net/ax25/{dev}/dama_slave_timeout) is still in
* (aka /proc/sys/net/ax25/{dev}/dama_slave_timeout) is still in
* 1/10th of a second.
* 1/10th of a second.
...
@@ -58,7 +51,8 @@ static void ax25_ds_add_timer(ax25_dev *ax25_dev)
...
@@ -58,7 +51,8 @@ static void ax25_ds_add_timer(ax25_dev *ax25_dev)
void
ax25_ds_del_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
)
void
ax25_ds_set_timer
(
ax25_dev
*
ax25_dev
)
...
@@ -80,15 +74,16 @@ static void ax25_ds_timeout(unsigned long arg)
...
@@ -80,15 +74,16 @@ static void ax25_ds_timeout(unsigned long arg)
{
{
ax25_dev
*
ax25_dev
=
(
struct
ax25_dev
*
)
arg
;
ax25_dev
*
ax25_dev
=
(
struct
ax25_dev
*
)
arg
;
ax25_cb
*
ax25
;
ax25_cb
*
ax25
;
if
(
ax25_dev
==
NULL
||
!
ax25_dev
->
dama
.
slave
)
if
(
ax25_dev
==
NULL
||
!
ax25_dev
->
dama
.
slave
)
return
;
/* Yikes! */
return
;
/* Yikes! */
if
(
!
ax25_dev
->
dama
.
slave_timeout
||
--
ax25_dev
->
dama
.
slave_timeout
)
{
if
(
!
ax25_dev
->
dama
.
slave_timeout
||
--
ax25_dev
->
dama
.
slave_timeout
)
{
ax25_ds_set_timer
(
ax25_dev
);
ax25_ds_set_timer
(
ax25_dev
);
return
;
return
;
}
}
spin_lock_bh
(
&
ax25_list_lock
);
for
(
ax25
=
ax25_list
;
ax25
!=
NULL
;
ax25
=
ax25
->
next
)
{
for
(
ax25
=
ax25_list
;
ax25
!=
NULL
;
ax25
=
ax25
->
next
)
{
if
(
ax25
->
ax25_dev
!=
ax25_dev
||
!
(
ax25
->
condition
&
AX25_COND_DAMA_MODE
))
if
(
ax25
->
ax25_dev
!=
ax25_dev
||
!
(
ax25
->
condition
&
AX25_COND_DAMA_MODE
))
continue
;
continue
;
...
@@ -96,7 +91,8 @@ static void ax25_ds_timeout(unsigned long arg)
...
@@ -96,7 +91,8 @@ static void ax25_ds_timeout(unsigned long arg)
ax25_send_control
(
ax25
,
AX25_DISC
,
AX25_POLLON
,
AX25_COMMAND
);
ax25_send_control
(
ax25
,
AX25_DISC
,
AX25_POLLON
,
AX25_COMMAND
);
ax25_disconnect
(
ax25
,
ETIMEDOUT
);
ax25_disconnect
(
ax25
,
ETIMEDOUT
);
}
}
spin_unlock_bh
(
&
ax25_list_lock
);
ax25_dev_dama_off
(
ax25_dev
);
ax25_dev_dama_off
(
ax25_dev
);
}
}
...
@@ -104,33 +100,33 @@ void ax25_ds_heartbeat_expiry(ax25_cb *ax25)
...
@@ -104,33 +100,33 @@ void ax25_ds_heartbeat_expiry(ax25_cb *ax25)
{
{
switch
(
ax25
->
state
)
{
switch
(
ax25
->
state
)
{
case
AX25_STATE_0
:
case
AX25_STATE_0
:
/* Magic here: If we listen() and a new link dies before it
/* Magic here: If we listen() and a new link dies before it
is accepted() it isn't 'dead' so doesn't get removed. */
is accepted() it isn't 'dead' so doesn't get removed. */
if
(
ax25
->
sk
==
NULL
||
ax25
->
sk
->
destroy
||
(
ax25
->
sk
->
state
==
TCP_LISTEN
&&
ax25
->
sk
->
dead
))
{
if
(
ax25
->
sk
==
NULL
||
ax25
->
sk
->
destroy
||
(
ax25
->
sk
->
state
==
TCP_LISTEN
&&
ax25
->
sk
->
dead
))
{
ax25_destroy_socket
(
ax25
);
ax25_destroy_socket
(
ax25
);
return
;
return
;
}
break
;
case
AX25_STATE_3
:
/*
* Check the state of the receive buffer.
*/
if
(
ax25
->
sk
!=
NULL
)
{
if
(
atomic_read
(
&
ax25
->
sk
->
rmem_alloc
)
<
(
ax25
->
sk
->
rcvbuf
/
2
)
&&
(
ax25
->
condition
&
AX25_COND_OWN_RX_BUSY
))
{
ax25
->
condition
&=
~
AX25_COND_OWN_RX_BUSY
;
ax25
->
condition
&=
~
AX25_COND_ACK_PENDING
;
break
;
}
}
break
;
}
break
;
case
AX25_STATE_3
:
/*
* Check the state of the receive buffer.
*/
if
(
ax25
->
sk
!=
NULL
)
{
if
(
atomic_read
(
&
ax25
->
sk
->
rmem_alloc
)
<
(
ax25
->
sk
->
rcvbuf
/
2
)
&&
(
ax25
->
condition
&
AX25_COND_OWN_RX_BUSY
))
{
ax25
->
condition
&=
~
AX25_COND_OWN_RX_BUSY
;
ax25
->
condition
&=
~
AX25_COND_ACK_PENDING
;
break
;
}
}
break
;
}
}
ax25_start_heartbeat
(
ax25
);
ax25_start_heartbeat
(
ax25
);
}
}
/* dl1bke 960114: T3 works much like the IDLE timeout, but
/* dl1bke 960114: T3 works much like the IDLE timeout, but
* gets reloaded with every frame for this
* gets reloaded with every frame for this
* connection.
* connection.
...
@@ -168,7 +164,7 @@ void ax25_ds_idletimer_expiry(ax25_cb *ax25)
...
@@ -168,7 +164,7 @@ void ax25_ds_idletimer_expiry(ax25_cb *ax25)
}
}
/* dl1bke 960114: The DAMA protocol requires to send data and SABM/DISC
/* dl1bke 960114: The DAMA protocol requires to send data and SABM/DISC
* within the poll of any connected channel. Remember
* within the poll of any connected channel. Remember
* that we are not allowed to send anything unless we
* that we are not allowed to send anything unless we
* get polled by the Master.
* get polled by the Master.
*
*
...
@@ -176,48 +172,47 @@ void ax25_ds_idletimer_expiry(ax25_cb *ax25)
...
@@ -176,48 +172,47 @@ void ax25_ds_idletimer_expiry(ax25_cb *ax25)
* ax25_enquiry_response().
* ax25_enquiry_response().
*/
*/
void
ax25_ds_t1_timeout
(
ax25_cb
*
ax25
)
void
ax25_ds_t1_timeout
(
ax25_cb
*
ax25
)
{
{
switch
(
ax25
->
state
)
{
switch
(
ax25
->
state
)
{
case
AX25_STATE_1
:
case
AX25_STATE_1
:
if
(
ax25
->
n2count
==
ax25
->
n2
)
{
if
(
ax25
->
n2count
==
ax25
->
n2
)
{
if
(
ax25
->
modulus
==
AX25_MODULUS
)
{
if
(
ax25
->
modulus
==
AX25_MODULUS
)
{
ax25_disconnect
(
ax25
,
ETIMEDOUT
);
return
;
}
else
{
ax25
->
modulus
=
AX25_MODULUS
;
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_WINDOW
];
ax25
->
n2count
=
0
;
ax25_send_control
(
ax25
,
AX25_SABM
,
AX25_POLLOFF
,
AX25_COMMAND
);
}
}
else
{
ax25
->
n2count
++
;
if
(
ax25
->
modulus
==
AX25_MODULUS
)
ax25_send_control
(
ax25
,
AX25_SABM
,
AX25_POLLOFF
,
AX25_COMMAND
);
else
ax25_send_control
(
ax25
,
AX25_SABME
,
AX25_POLLOFF
,
AX25_COMMAND
);
}
break
;
case
AX25_STATE_2
:
if
(
ax25
->
n2count
==
ax25
->
n2
)
{
ax25_send_control
(
ax25
,
AX25_DISC
,
AX25_POLLON
,
AX25_COMMAND
);
ax25_disconnect
(
ax25
,
ETIMEDOUT
);
return
;
}
else
{
ax25
->
n2count
++
;
}
break
;
case
AX25_STATE_3
:
if
(
ax25
->
n2count
==
ax25
->
n2
)
{
ax25_send_control
(
ax25
,
AX25_DM
,
AX25_POLLON
,
AX25_RESPONSE
);
ax25_disconnect
(
ax25
,
ETIMEDOUT
);
ax25_disconnect
(
ax25
,
ETIMEDOUT
);
return
;
return
;
}
else
{
}
else
{
ax25
->
n2count
++
;
ax25
->
modulus
=
AX25_MODULUS
;
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_WINDOW
];
ax25
->
n2count
=
0
;
ax25_send_control
(
ax25
,
AX25_SABM
,
AX25_POLLOFF
,
AX25_COMMAND
);
}
}
break
;
}
else
{
ax25
->
n2count
++
;
if
(
ax25
->
modulus
==
AX25_MODULUS
)
ax25_send_control
(
ax25
,
AX25_SABM
,
AX25_POLLOFF
,
AX25_COMMAND
);
else
ax25_send_control
(
ax25
,
AX25_SABME
,
AX25_POLLOFF
,
AX25_COMMAND
);
}
break
;
case
AX25_STATE_2
:
if
(
ax25
->
n2count
==
ax25
->
n2
)
{
ax25_send_control
(
ax25
,
AX25_DISC
,
AX25_POLLON
,
AX25_COMMAND
);
ax25_disconnect
(
ax25
,
ETIMEDOUT
);
return
;
}
else
{
ax25
->
n2count
++
;
}
break
;
case
AX25_STATE_3
:
if
(
ax25
->
n2count
==
ax25
->
n2
)
{
ax25_send_control
(
ax25
,
AX25_DM
,
AX25_POLLON
,
AX25_RESPONSE
);
ax25_disconnect
(
ax25
,
ETIMEDOUT
);
return
;
}
else
{
ax25
->
n2count
++
;
}
break
;
}
}
ax25_calculate_t1
(
ax25
);
ax25_calculate_t1
(
ax25
);
...
...
net/ax25/ax25_iface.c
View file @
b331768e
/*
/*
* 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) 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.
*
* History
* AX.25 036 Jonathan(G4KLX) Split from ax25_timer.c.
*/
*/
#include <linux/config.h>
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
...
@@ -20,6 +13,7 @@
...
@@ -20,6 +13,7 @@
#include <linux/in.h>
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/sockios.h>
...
@@ -40,22 +34,25 @@ static struct protocol_struct {
...
@@ -40,22 +34,25 @@ static struct protocol_struct {
unsigned
int
pid
;
unsigned
int
pid
;
int
(
*
func
)(
struct
sk_buff
*
,
ax25_cb
*
);
int
(
*
func
)(
struct
sk_buff
*
,
ax25_cb
*
);
}
*
protocol_list
;
}
*
protocol_list
;
static
rwlock_t
protocol_list_lock
=
RW_LOCK_UNLOCKED
;
static
struct
linkfail_struct
{
static
struct
linkfail_struct
{
struct
linkfail_struct
*
next
;
struct
linkfail_struct
*
next
;
void
(
*
func
)(
ax25_cb
*
,
int
);
void
(
*
func
)(
ax25_cb
*
,
int
);
}
*
linkfail_list
;
}
*
linkfail_list
;
static
spinlock_t
linkfail_lock
=
SPIN_LOCK_UNLOCKED
;
static
struct
listen_struct
{
static
struct
listen_struct
{
struct
listen_struct
*
next
;
struct
listen_struct
*
next
;
ax25_address
callsign
;
ax25_address
callsign
;
struct
net_device
*
dev
;
struct
net_device
*
dev
;
}
*
listen_list
;
}
*
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
;
struct
protocol_struct
*
protocol
;
unsigned
long
flags
;
if
(
pid
==
AX25_P_TEXT
||
pid
==
AX25_P_SEGMENT
)
if
(
pid
==
AX25_P_TEXT
||
pid
==
AX25_P_SEGMENT
)
return
0
;
return
0
;
...
@@ -69,31 +66,28 @@ int ax25_protocol_register(unsigned int pid, int (*func)(struct sk_buff *, ax25_
...
@@ -69,31 +66,28 @@ int ax25_protocol_register(unsigned int pid, int (*func)(struct sk_buff *, ax25_
protocol
->
pid
=
pid
;
protocol
->
pid
=
pid
;
protocol
->
func
=
func
;
protocol
->
func
=
func
;
save_flags
(
flags
);
write_lock
(
&
protocol_list_lock
);
cli
();
protocol
->
next
=
protocol_list
;
protocol
->
next
=
protocol_list
;
protocol_list
=
protocol
;
protocol_list
=
protocol
;
write_unlock
(
&
protocol_list_lock
);
restore_flags
(
flags
);
return
1
;
return
1
;
}
}
void
ax25_protocol_release
(
unsigned
int
pid
)
void
ax25_protocol_release
(
unsigned
int
pid
)
{
{
struct
protocol_struct
*
s
,
*
protocol
=
protocol_list
;
struct
protocol_struct
*
s
,
*
protocol
;
unsigned
long
flags
;
if
(
protocol
==
NULL
)
write_lock
(
&
protocol_list_lock
);
protocol
=
protocol_list
;
if
(
protocol
==
NULL
)
{
write_unlock
(
&
protocol_list_lock
);
return
;
return
;
}
save_flags
(
flags
);
cli
();
if
(
protocol
->
pid
==
pid
)
{
if
(
protocol
->
pid
==
pid
)
{
protocol_list
=
protocol
->
next
;
protocol_list
=
protocol
->
next
;
restore_flags
(
flags
);
write_unlock
(
&
protocol_list_lock
);
kfree
(
protocol
);
kfree
(
protocol
);
return
;
return
;
}
}
...
@@ -102,52 +96,45 @@ void ax25_protocol_release(unsigned int pid)
...
@@ -102,52 +96,45 @@ void ax25_protocol_release(unsigned int pid)
if
(
protocol
->
next
->
pid
==
pid
)
{
if
(
protocol
->
next
->
pid
==
pid
)
{
s
=
protocol
->
next
;
s
=
protocol
->
next
;
protocol
->
next
=
protocol
->
next
->
next
;
protocol
->
next
=
protocol
->
next
->
next
;
restore_flags
(
flags
);
write_unlock
(
&
protocol_list_lock
);
kfree
(
s
);
kfree
(
s
);
return
;
return
;
}
}
protocol
=
protocol
->
next
;
protocol
=
protocol
->
next
;
}
}
write_unlock
(
&
protocol_list_lock
);
restore_flags
(
flags
);
}
}
int
ax25_linkfail_register
(
void
(
*
func
)(
ax25_cb
*
,
int
))
int
ax25_linkfail_register
(
void
(
*
func
)(
ax25_cb
*
,
int
))
{
{
struct
linkfail_struct
*
linkfail
;
struct
linkfail_struct
*
linkfail
;
unsigned
long
flags
;
if
((
linkfail
=
kmalloc
(
sizeof
(
*
linkfail
),
GFP_ATOMIC
))
==
NULL
)
if
((
linkfail
=
kmalloc
(
sizeof
(
*
linkfail
),
GFP_ATOMIC
))
==
NULL
)
return
0
;
return
0
;
linkfail
->
func
=
func
;
linkfail
->
func
=
func
;
save_flags
(
flags
);
spin_lock_bh
(
&
linkfail_lock
);
cli
();
linkfail
->
next
=
linkfail_list
;
linkfail
->
next
=
linkfail_list
;
linkfail_list
=
linkfail
;
linkfail_list
=
linkfail
;
spin_unlock_bh
(
&
linkfail_lock
);
restore_flags
(
flags
);
return
1
;
return
1
;
}
}
void
ax25_linkfail_release
(
void
(
*
func
)(
ax25_cb
*
,
int
))
void
ax25_linkfail_release
(
void
(
*
func
)(
ax25_cb
*
,
int
))
{
{
struct
linkfail_struct
*
s
,
*
linkfail
=
linkfail_list
;
struct
linkfail_struct
*
s
,
*
linkfail
;
unsigned
long
flags
;
spin_lock_bh
(
&
linkfail_lock
);
linkfail
=
linkfail_list
;
if
(
linkfail
==
NULL
)
if
(
linkfail
==
NULL
)
return
;
return
;
save_flags
(
flags
);
cli
();
if
(
linkfail
->
func
==
func
)
{
if
(
linkfail
->
func
==
func
)
{
linkfail_list
=
linkfail
->
next
;
linkfail_list
=
linkfail
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
linkfail_lock
);
kfree
(
linkfail
);
kfree
(
linkfail
);
return
;
return
;
}
}
...
@@ -156,21 +143,19 @@ void ax25_linkfail_release(void (*func)(ax25_cb *, int))
...
@@ -156,21 +143,19 @@ void ax25_linkfail_release(void (*func)(ax25_cb *, int))
if
(
linkfail
->
next
->
func
==
func
)
{
if
(
linkfail
->
next
->
func
==
func
)
{
s
=
linkfail
->
next
;
s
=
linkfail
->
next
;
linkfail
->
next
=
linkfail
->
next
->
next
;
linkfail
->
next
=
linkfail
->
next
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
linkfail_lock
);
kfree
(
s
);
kfree
(
s
);
return
;
return
;
}
}
linkfail
=
linkfail
->
next
;
linkfail
=
linkfail
->
next
;
}
}
spin_unlock_bh
(
&
linkfail_lock
);
restore_flags
(
flags
);
}
}
int
ax25_listen_register
(
ax25_address
*
callsign
,
struct
net_device
*
dev
)
int
ax25_listen_register
(
ax25_address
*
callsign
,
struct
net_device
*
dev
)
{
{
struct
listen_struct
*
listen
;
struct
listen_struct
*
listen
;
unsigned
long
flags
;
if
(
ax25_listen_mine
(
callsign
,
dev
))
if
(
ax25_listen_mine
(
callsign
,
dev
))
return
0
;
return
0
;
...
@@ -181,31 +166,26 @@ int ax25_listen_register(ax25_address *callsign, struct net_device *dev)
...
@@ -181,31 +166,26 @@ int ax25_listen_register(ax25_address *callsign, struct net_device *dev)
listen
->
callsign
=
*
callsign
;
listen
->
callsign
=
*
callsign
;
listen
->
dev
=
dev
;
listen
->
dev
=
dev
;
save_flags
(
flags
);
spin_lock_bh
(
&
listen_lock
);
cli
();
listen
->
next
=
listen_list
;
listen
->
next
=
listen_list
;
listen_list
=
listen
;
listen_list
=
listen
;
spin_unlock_bh
(
&
listen_lock
);
restore_flags
(
flags
);
return
1
;
return
1
;
}
}
void
ax25_listen_release
(
ax25_address
*
callsign
,
struct
net_device
*
dev
)
void
ax25_listen_release
(
ax25_address
*
callsign
,
struct
net_device
*
dev
)
{
{
struct
listen_struct
*
s
,
*
listen
=
listen_list
;
struct
listen_struct
*
s
,
*
listen
;
unsigned
long
flags
;
spin_lock_bh
(
&
listen_lock
);
listen
=
listen_list
;
if
(
listen
==
NULL
)
if
(
listen
==
NULL
)
return
;
return
;
save_flags
(
flags
);
cli
();
if
(
ax25cmp
(
&
listen
->
callsign
,
callsign
)
==
0
&&
listen
->
dev
==
dev
)
{
if
(
ax25cmp
(
&
listen
->
callsign
,
callsign
)
==
0
&&
listen
->
dev
==
dev
)
{
listen_list
=
listen
->
next
;
listen_list
=
listen
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
listen_lock
);
kfree
(
listen
);
kfree
(
listen
);
return
;
return
;
}
}
...
@@ -214,35 +194,41 @@ void ax25_listen_release(ax25_address *callsign, struct net_device *dev)
...
@@ -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
)
{
if
(
ax25cmp
(
&
listen
->
next
->
callsign
,
callsign
)
==
0
&&
listen
->
next
->
dev
==
dev
)
{
s
=
listen
->
next
;
s
=
listen
->
next
;
listen
->
next
=
listen
->
next
->
next
;
listen
->
next
=
listen
->
next
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
listen_lock
);
kfree
(
s
);
kfree
(
s
);
return
;
return
;
}
}
listen
=
listen
->
next
;
listen
=
listen
->
next
;
}
}
spin_unlock_bh
(
&
listen_lock
);
restore_flags
(
flags
);
}
}
int
(
*
ax25_protocol_function
(
unsigned
int
pid
))(
struct
sk_buff
*
,
ax25_cb
*
)
int
(
*
ax25_protocol_function
(
unsigned
int
pid
))(
struct
sk_buff
*
,
ax25_cb
*
)
{
{
int
(
*
res
)(
struct
sk_buff
*
,
ax25_cb
*
)
=
NULL
;
struct
protocol_struct
*
protocol
;
struct
protocol_struct
*
protocol
;
read_lock
(
&
protocol_list_lock
);
for
(
protocol
=
protocol_list
;
protocol
!=
NULL
;
protocol
=
protocol
->
next
)
for
(
protocol
=
protocol_list
;
protocol
!=
NULL
;
protocol
=
protocol
->
next
)
if
(
protocol
->
pid
==
pid
)
if
(
protocol
->
pid
==
pid
)
{
return
protocol
->
func
;
res
=
protocol
->
func
;
break
;
}
read_unlock
(
&
protocol_list_lock
);
return
NULL
;
return
res
;
}
}
int
ax25_listen_mine
(
ax25_address
*
callsign
,
struct
net_device
*
dev
)
int
ax25_listen_mine
(
ax25_address
*
callsign
,
struct
net_device
*
dev
)
{
{
struct
listen_struct
*
listen
;
struct
listen_struct
*
listen
;
spin_lock_bh
(
&
listen_lock
);
for
(
listen
=
listen_list
;
listen
!=
NULL
;
listen
=
listen
->
next
)
for
(
listen
=
listen_list
;
listen
!=
NULL
;
listen
=
listen
->
next
)
if
(
ax25cmp
(
&
listen
->
callsign
,
callsign
)
==
0
&&
(
listen
->
dev
==
dev
||
listen
->
dev
==
NULL
))
if
(
ax25cmp
(
&
listen
->
callsign
,
callsign
)
==
0
&&
(
listen
->
dev
==
dev
||
listen
->
dev
==
NULL
))
return
1
;
return
1
;
spin_unlock_bh
(
&
listen_lock
);
return
0
;
return
0
;
}
}
...
@@ -251,18 +237,24 @@ void ax25_link_failed(ax25_cb *ax25, int reason)
...
@@ -251,18 +237,24 @@ void ax25_link_failed(ax25_cb *ax25, int reason)
{
{
struct
linkfail_struct
*
linkfail
;
struct
linkfail_struct
*
linkfail
;
spin_lock_bh
(
&
linkfail_lock
);
for
(
linkfail
=
linkfail_list
;
linkfail
!=
NULL
;
linkfail
=
linkfail
->
next
)
for
(
linkfail
=
linkfail_list
;
linkfail
!=
NULL
;
linkfail
=
linkfail
->
next
)
(
linkfail
->
func
)(
ax25
,
reason
);
(
linkfail
->
func
)(
ax25
,
reason
);
spin_unlock_bh
(
&
linkfail_lock
);
}
}
int
ax25_protocol_is_registered
(
unsigned
int
pid
)
int
ax25_protocol_is_registered
(
unsigned
int
pid
)
{
{
struct
protocol_struct
*
protocol
;
struct
protocol_struct
*
protocol
;
int
res
=
0
;
read_lock
(
&
protocol_list_lock
);
for
(
protocol
=
protocol_list
;
protocol
!=
NULL
;
protocol
=
protocol
->
next
)
for
(
protocol
=
protocol_list
;
protocol
!=
NULL
;
protocol
=
protocol
->
next
)
if
(
protocol
->
pid
==
pid
)
if
(
protocol
->
pid
==
pid
)
{
return
1
;
res
=
1
;
break
;
}
read_unlock
(
&
protocol_list_lock
);
return
0
;
return
res
;
}
}
net/ax25/ax25_in.c
View file @
b331768e
/*
/*
* 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)
* This module:
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* This module is free software; you can redistribute it and/or
* Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
* 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.
*/
*/
#include <linux/config.h>
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
...
@@ -146,7 +116,7 @@ int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb)
...
@@ -146,7 +116,7 @@ int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb)
#ifdef CONFIG_INET
#ifdef CONFIG_INET
if
(
pid
==
AX25_P_IP
)
{
if
(
pid
==
AX25_P_IP
)
{
/* working around a TCP bug to keep additional listeners
/* working around a TCP bug to keep additional listeners
* happy. TCP re-uses the buffer and destroys the original
* happy. TCP re-uses the buffer and destroys the original
* content.
* content.
*/
*/
...
@@ -199,37 +169,33 @@ static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, i
...
@@ -199,37 +169,33 @@ static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, i
return
0
;
return
0
;
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
queued
=
ax25_std_frame_in
(
ax25
,
skb
,
type
);
queued
=
ax25_std_frame_in
(
ax25
,
skb
,
type
);
break
;
break
;
#ifdef CONFIG_AX25_DAMA_SLAVE
#ifdef CONFIG_AX25_DAMA_SLAVE
case
AX25_PROTO_DAMA_SLAVE
:
case
AX25_PROTO_DAMA_SLAVE
:
if
(
dama
||
ax25
->
ax25_dev
->
dama
.
slave
)
if
(
dama
||
ax25
->
ax25_dev
->
dama
.
slave
)
queued
=
ax25_ds_frame_in
(
ax25
,
skb
,
type
);
queued
=
ax25_ds_frame_in
(
ax25
,
skb
,
type
);
else
else
queued
=
ax25_std_frame_in
(
ax25
,
skb
,
type
);
queued
=
ax25_std_frame_in
(
ax25
,
skb
,
type
);
break
;
break
;
#endif
#endif
}
}
return
queued
;
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
;
ax25_address
src
,
dest
,
*
next_digi
=
NULL
;
struct
sock
*
sk
;
int
type
=
0
,
mine
=
0
,
dama
;
int
type
=
0
;
struct
sock
*
make
,
*
sk
,
*
raw
;
ax25_digi
dp
,
reverse_dp
;
ax25_digi
dp
,
reverse_dp
;
ax25_cb
*
ax25
;
ax25_cb
*
ax25
;
ax25_address
src
,
dest
;
ax25_address
*
next_digi
=
NULL
;
ax25_dev
*
ax25_dev
;
ax25_dev
*
ax25_dev
;
struct
sock
*
raw
;
int
mine
=
0
;
int
dama
;
/*
/*
* Process the AX.25/LAPB frame.
* 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
...
@@ -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
)
{
if
((
*
skb
->
data
&
~
0x10
)
==
AX25_UI
&&
dp
.
lastrepeat
+
1
==
dp
.
ndigi
)
{
skb
->
h
.
raw
=
skb
->
data
+
2
;
/* skip control and pid */
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
]);
ax25_send_to_raw
(
raw
,
skb
,
skb
->
data
[
1
]);
release_sock
(
raw
);
}
if
(
!
mine
&&
ax25cmp
(
&
dest
,
(
ax25_address
*
)
dev
->
broadcast
)
!=
0
)
{
if
(
!
mine
&&
ax25cmp
(
&
dest
,
(
ax25_address
*
)
dev
->
broadcast
)
!=
0
)
{
kfree_skb
(
skb
);
kfree_skb
(
skb
);
...
@@ -285,47 +253,49 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d
...
@@ -285,47 +253,49 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d
/* Now we are pointing at the pid byte */
/* Now we are pointing at the pid byte */
switch
(
skb
->
data
[
1
])
{
switch
(
skb
->
data
[
1
])
{
#ifdef CONFIG_INET
#ifdef CONFIG_INET
case
AX25_P_IP
:
case
AX25_P_IP
:
skb_pull
(
skb
,
2
);
/* drop PID/CTRL */
skb_pull
(
skb
,
2
);
/* drop PID/CTRL */
skb
->
h
.
raw
=
skb
->
data
;
skb
->
h
.
raw
=
skb
->
data
;
skb
->
nh
.
raw
=
skb
->
data
;
skb
->
nh
.
raw
=
skb
->
data
;
skb
->
dev
=
dev
;
skb
->
dev
=
dev
;
skb
->
pkt_type
=
PACKET_HOST
;
skb
->
pkt_type
=
PACKET_HOST
;
skb
->
protocol
=
htons
(
ETH_P_IP
);
skb
->
protocol
=
htons
(
ETH_P_IP
);
ip_rcv
(
skb
,
dev
,
ptype
);
/* Note ptype here is the wrong one, fix me later */
ip_rcv
(
skb
,
dev
,
ptype
);
/* Note ptype here is the wrong one, fix me later */
break
;
break
;
case
AX25_P_ARP
:
case
AX25_P_ARP
:
skb_pull
(
skb
,
2
);
skb_pull
(
skb
,
2
);
skb
->
h
.
raw
=
skb
->
data
;
skb
->
h
.
raw
=
skb
->
data
;
skb
->
nh
.
raw
=
skb
->
data
;
skb
->
nh
.
raw
=
skb
->
data
;
skb
->
dev
=
dev
;
skb
->
dev
=
dev
;
skb
->
pkt_type
=
PACKET_HOST
;
skb
->
pkt_type
=
PACKET_HOST
;
skb
->
protocol
=
htons
(
ETH_P_ARP
);
skb
->
protocol
=
htons
(
ETH_P_ARP
);
arp_rcv
(
skb
,
dev
,
ptype
);
/* Note ptype here is wrong... */
arp_rcv
(
skb
,
dev
,
ptype
);
/* Note ptype here is wrong... */
break
;
break
;
#endif
#endif
case
AX25_P_TEXT
:
case
AX25_P_TEXT
:
/* Now find a suitable dgram socket */
/* 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
(
atomic_read
(
&
sk
->
rmem_alloc
)
>=
sk
->
rcvbuf
)
{
if
(
sk
!=
NULL
)
{
kfree_skb
(
skb
);
if
(
atomic_read
(
&
sk
->
rmem_alloc
)
>=
sk
->
rcvbuf
)
{
}
else
{
/*
* Remove the control and PID.
*/
skb_pull
(
skb
,
2
);
if
(
sock_queue_rcv_skb
(
sk
,
skb
)
!=
0
)
kfree_skb
(
skb
);
}
}
else
{
kfree_skb
(
skb
);
kfree_skb
(
skb
);
}
else
{
/*
* Remove the control and PID.
*/
skb_pull
(
skb
,
2
);
if
(
sock_queue_rcv_skb
(
sk
,
skb
)
!=
0
)
kfree_skb
(
skb
);
}
}
break
;
release_sock
(
sk
);
}
else
{
kfree_skb
(
skb
);
}
break
;
default:
default:
kfree_skb
(
skb
);
/* Will scan SOCK_AX25 RAW sockets */
kfree_skb
(
skb
);
/* Will scan SOCK_AX25 RAW sockets */
break
;
break
;
}
}
return
0
;
return
0
;
...
@@ -349,9 +319,10 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d
...
@@ -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
)
{
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
* Process the frame. If it is queued up internally it
* free it immediately. This routine itself wakes the user context layers so we
* returns one otherwise we free it immediately. This
* do no further work
* routine itself wakes the user context layers so we do
* no further work
*/
*/
if
(
ax25_process_rx_frame
(
ax25
,
skb
,
type
,
dama
)
==
0
)
if
(
ax25_process_rx_frame
(
ax25
,
skb
,
type
,
dama
)
==
0
)
kfree_skb
(
skb
);
kfree_skb
(
skb
);
...
@@ -363,7 +334,8 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d
...
@@ -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) */
/* 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
* Never reply to a DM. Also ignore any connects for
* addresses that are not our interfaces and not a socket.
* 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
...
@@ -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
);
sk
=
ax25_find_listener
(
next_digi
,
1
,
dev
,
SOCK_SEQPACKET
);
if
(
sk
!=
NULL
)
{
if
(
sk
!=
NULL
)
{
if
(
sk
->
ack_backlog
==
sk
->
max_ack_backlog
||
(
make
=
ax25_make_new
(
sk
,
ax25_dev
))
==
NULL
)
{
if
(
sk
->
ack_backlog
==
sk
->
max_ack_backlog
||
if
(
mine
)
ax25_return_dm
(
dev
,
&
src
,
&
dest
,
&
dp
);
(
make
=
ax25_make_new
(
sk
,
ax25_dev
))
==
NULL
)
{
if
(
mine
)
ax25_return_dm
(
dev
,
&
src
,
&
dest
,
&
dp
);
kfree_skb
(
skb
);
kfree_skb
(
skb
);
return
0
;
return
0
;
}
}
...
@@ -486,4 +461,3 @@ int ax25_kiss_rcv(struct sk_buff *skb, struct net_device *dev,
...
@@ -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
);
return
ax25_rcv
(
skb
,
dev
,
(
ax25_address
*
)
dev
->
dev_addr
,
ptype
);
}
}
net/ax25/ax25_ip.c
View file @
b331768e
/*
/*
* 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) 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.
*
* History
* AX.25 036 Jonathan(G4KLX) Split from af_ax25.c.
*/
*/
#include <linux/config.h>
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
...
@@ -88,16 +81,16 @@ int ax25_encapsulate(struct sk_buff *skb, struct net_device *dev, unsigned short
...
@@ -88,16 +81,16 @@ int ax25_encapsulate(struct sk_buff *skb, struct net_device *dev, unsigned short
/* Append a suitable AX.25 PID */
/* Append a suitable AX.25 PID */
switch
(
type
)
{
switch
(
type
)
{
case
ETH_P_IP
:
case
ETH_P_IP
:
*
buff
++
=
AX25_P_IP
;
*
buff
++
=
AX25_P_IP
;
break
;
break
;
case
ETH_P_ARP
:
case
ETH_P_ARP
:
*
buff
++
=
AX25_P_ARP
;
*
buff
++
=
AX25_P_ARP
;
break
;
break
;
default:
default:
printk
(
KERN_ERR
"AX.25: ax25_encapsulate - wrong protocol type 0x%2.2x
\n
"
,
type
);
printk
(
KERN_ERR
"AX.25: ax25_encapsulate - wrong protocol type 0x%2.2x
\n
"
,
type
);
*
buff
++
=
0
;
*
buff
++
=
0
;
break
;
break
;
}
}
if
(
daddr
!=
NULL
)
if
(
daddr
!=
NULL
)
...
@@ -112,8 +105,8 @@ int ax25_rebuild_header(struct sk_buff *skb)
...
@@ -112,8 +105,8 @@ int ax25_rebuild_header(struct sk_buff *skb)
unsigned
char
*
bp
=
skb
->
data
;
unsigned
char
*
bp
=
skb
->
data
;
struct
net_device
*
dev
;
struct
net_device
*
dev
;
ax25_address
*
src
,
*
dst
;
ax25_address
*
src
,
*
dst
;
ax25_route
*
route
;
ax25_dev
*
ax25_dev
;
ax25_dev
*
ax25_dev
;
ax25_route
_route
,
*
route
=
&
_route
;
dst
=
(
ax25_address
*
)(
bp
+
1
);
dst
=
(
ax25_address
*
)(
bp
+
1
);
src
=
(
ax25_address
*
)(
bp
+
8
);
src
=
(
ax25_address
*
)(
bp
+
8
);
...
@@ -121,14 +114,15 @@ int ax25_rebuild_header(struct sk_buff *skb)
...
@@ -121,14 +114,15 @@ int ax25_rebuild_header(struct sk_buff *skb)
if
(
arp_find
(
bp
+
1
,
skb
))
if
(
arp_find
(
bp
+
1
,
skb
))
return
1
;
return
1
;
route
=
ax25_rt_find_route
(
dst
,
NULL
);
route
=
ax25_rt_find_route
(
route
,
dst
,
NULL
);
dev
=
route
->
dev
;
dev
=
route
->
dev
;
if
(
dev
==
NULL
)
if
(
dev
==
NULL
)
dev
=
skb
->
dev
;
dev
=
skb
->
dev
;
if
((
ax25_dev
=
ax25_dev_ax25dev
(
dev
))
==
NULL
)
if
((
ax25_dev
=
ax25_dev_ax25dev
(
dev
))
==
NULL
)
{
return
1
;
goto
put
;
}
if
(
bp
[
16
]
==
AX25_P_IP
)
{
if
(
bp
[
16
]
==
AX25_P_IP
)
{
if
(
route
->
ip_mode
==
'V'
||
(
route
->
ip_mode
==
' '
&&
ax25_dev
->
values
[
AX25_VALUES_IPDEFMODE
]))
{
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)
...
@@ -153,7 +147,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
if
((
ourskb
=
skb_copy
(
skb
,
GFP_ATOMIC
))
==
NULL
)
{
if
((
ourskb
=
skb_copy
(
skb
,
GFP_ATOMIC
))
==
NULL
)
{
kfree_skb
(
skb
);
kfree_skb
(
skb
);
return
1
;
goto
put
;
}
}
if
(
skb
->
sk
!=
NULL
)
if
(
skb
->
sk
!=
NULL
)
...
@@ -167,10 +161,10 @@ int ax25_rebuild_header(struct sk_buff *skb)
...
@@ -167,10 +161,10 @@ int ax25_rebuild_header(struct sk_buff *skb)
skb_pull
(
ourskb
,
AX25_HEADER_LEN
-
1
);
/* Keep PID */
skb_pull
(
ourskb
,
AX25_HEADER_LEN
-
1
);
/* Keep PID */
ourskb
->
nh
.
raw
=
ourskb
->
data
;
ourskb
->
nh
.
raw
=
ourskb
->
data
;
ax25_send_frame
(
ourskb
,
ax25_dev
->
values
[
AX25_VALUES_PACLEN
],
&
src_c
,
ax25_send_frame
(
ourskb
,
ax25_dev
->
values
[
AX25_VALUES_PACLEN
],
&
src_c
,
&
dst_c
,
route
->
digipeat
,
dev
);
&
dst_c
,
route
->
digipeat
,
dev
);
return
1
;
goto
put
;
}
}
}
}
...
@@ -187,7 +181,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
...
@@ -187,7 +181,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
if
(
route
->
digipeat
!=
NULL
)
{
if
(
route
->
digipeat
!=
NULL
)
{
if
((
ourskb
=
ax25_rt_build_path
(
skb
,
src
,
dst
,
route
->
digipeat
))
==
NULL
)
{
if
((
ourskb
=
ax25_rt_build_path
(
skb
,
src
,
dst
,
route
->
digipeat
))
==
NULL
)
{
kfree_skb
(
skb
);
kfree_skb
(
skb
);
return
1
;
goto
put
;
}
}
skb
=
ourskb
;
skb
=
ourskb
;
...
@@ -197,6 +191,9 @@ int ax25_rebuild_header(struct sk_buff *skb)
...
@@ -197,6 +191,9 @@ int ax25_rebuild_header(struct sk_buff *skb)
ax25_queue_xmit
(
skb
);
ax25_queue_xmit
(
skb
);
put:
ax25_put_route
(
route
);
return
1
;
return
1
;
}
}
...
...
net/ax25/ax25_out.c
View file @
b331768e
/*
/*
* 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)
* This module:
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* 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)
*/
*/
#include <linux/config.h>
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
...
@@ -44,6 +18,7 @@
...
@@ -44,6 +18,7 @@
#include <linux/timer.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/sockios.h>
#include <linux/spinlock.h>
#include <linux/net.h>
#include <linux/net.h>
#include <net/ax25.h>
#include <net/ax25.h>
#include <linux/inet.h>
#include <linux/inet.h>
...
@@ -57,6 +32,8 @@
...
@@ -57,6 +32,8 @@
#include <linux/mm.h>
#include <linux/mm.h>
#include <linux/interrupt.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_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
;
ax25_dev
*
ax25_dev
;
...
@@ -101,18 +78,18 @@ ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax2
...
@@ -101,18 +78,18 @@ ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax2
}
}
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
ax25_std_establish_data_link
(
ax25
);
ax25_std_establish_data_link
(
ax25
);
break
;
break
;
#ifdef CONFIG_AX25_DAMA_SLAVE
#ifdef CONFIG_AX25_DAMA_SLAVE
case
AX25_PROTO_DAMA_SLAVE
:
case
AX25_PROTO_DAMA_SLAVE
:
if
(
ax25_dev
->
dama
.
slave
)
if
(
ax25_dev
->
dama
.
slave
)
ax25_ds_establish_data_link
(
ax25
);
ax25_ds_establish_data_link
(
ax25
);
else
else
ax25_std_establish_data_link
(
ax25
);
ax25_std_establish_data_link
(
ax25
);
break
;
break
;
#endif
#endif
}
}
...
@@ -138,7 +115,6 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
...
@@ -138,7 +115,6 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
struct
sk_buff
*
skbn
;
struct
sk_buff
*
skbn
;
unsigned
char
*
p
;
unsigned
char
*
p
;
int
frontlen
,
len
,
fragno
,
ka9qfrag
,
first
=
1
;
int
frontlen
,
len
,
fragno
,
ka9qfrag
,
first
=
1
;
long
flags
;
if
((
skb
->
len
-
1
)
>
paclen
)
{
if
((
skb
->
len
-
1
)
>
paclen
)
{
if
(
*
skb
->
data
==
AX25_P_TEXT
)
{
if
(
*
skb
->
data
==
AX25_P_TEXT
)
{
...
@@ -155,20 +131,18 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
...
@@ -155,20 +131,18 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
frontlen
=
skb_headroom
(
skb
);
/* Address space + CTRL */
frontlen
=
skb_headroom
(
skb
);
/* Address space + CTRL */
while
(
skb
->
len
>
0
)
{
while
(
skb
->
len
>
0
)
{
save_flags
(
flags
);
spin_lock_bh
(
&
ax25_frag_lock
);
cli
();
if
((
skbn
=
alloc_skb
(
paclen
+
2
+
frontlen
,
GFP_ATOMIC
))
==
NULL
)
{
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
"
);
printk
(
KERN_CRIT
"AX.25: ax25_output - out of memory
\n
"
);
return
;
return
;
}
}
if
(
skb
->
sk
!=
NULL
)
if
(
skb
->
sk
!=
NULL
)
skb_set_owner_w
(
skbn
,
skb
->
sk
);
skb_set_owner_w
(
skbn
,
skb
->
sk
);
restore_flags
(
flags
);
spin_unlock_bh
(
&
ax25_frag_lock
);
len
=
(
paclen
>
skb
->
len
)
?
skb
->
len
:
paclen
;
len
=
(
paclen
>
skb
->
len
)
?
skb
->
len
:
paclen
;
if
(
ka9qfrag
==
1
)
{
if
(
ka9qfrag
==
1
)
{
...
@@ -202,24 +176,24 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
...
@@ -202,24 +176,24 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
}
}
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
ax25_kick
(
ax25
);
ax25_kick
(
ax25
);
break
;
break
;
#ifdef CONFIG_AX25_DAMA_SLAVE
#ifdef CONFIG_AX25_DAMA_SLAVE
/*
/*
* A DAMA slave is _required_ to work as normal AX.25L2V2
* A DAMA slave is _required_ to work as normal AX.25L2V2
* if no DAMA master is available.
* if no DAMA master is available.
*/
*/
case
AX25_PROTO_DAMA_SLAVE
:
case
AX25_PROTO_DAMA_SLAVE
:
if
(
!
ax25
->
ax25_dev
->
dama
.
slave
)
ax25_kick
(
ax25
);
if
(
!
ax25
->
ax25_dev
->
dama
.
slave
)
ax25_kick
(
ax25
);
break
;
break
;
#endif
#endif
}
}
}
}
/*
/*
* This procedure is passed a buffer descriptor for an iframe. It builds
* This procedure is passed a buffer descriptor for an iframe. It builds
* the rest of the control part of the frame and then writes it out.
* the rest of the control part of the frame and then writes it out.
*/
*/
...
@@ -305,15 +279,15 @@ void ax25_kick(ax25_cb *ax25)
...
@@ -305,15 +279,15 @@ void ax25_kick(ax25_cb *ax25)
* in DAMA mode.
* in DAMA mode.
*/
*/
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
ax25_send_iframe
(
ax25
,
skbn
,
(
last
)
?
AX25_POLLON
:
AX25_POLLOFF
);
ax25_send_iframe
(
ax25
,
skbn
,
(
last
)
?
AX25_POLLON
:
AX25_POLLOFF
);
break
;
break
;
#ifdef CONFIG_AX25_DAMA_SLAVE
#ifdef CONFIG_AX25_DAMA_SLAVE
case
AX25_PROTO_DAMA_SLAVE
:
case
AX25_PROTO_DAMA_SLAVE
:
ax25_send_iframe
(
ax25
,
skbn
,
AX25_POLLOFF
);
ax25_send_iframe
(
ax25
,
skbn
,
AX25_POLLOFF
);
break
;
break
;
#endif
#endif
}
}
...
...
net/ax25/ax25_route.c
View file @
b331768e
/*
/*
* 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)
* This module:
* Copyright (C) Steven Whitehouse GW7RRM (stevew@acm.org)
* This module is free software; you can redistribute it and/or
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* modify it under the terms of the GNU General Public License
* Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
* as published by the Free Software Foundation; either version
* Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
* 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/
*/
*/
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
#include <linux/timer.h>
#include <linux/in.h>
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/sched.h>
...
@@ -56,6 +27,7 @@
...
@@ -56,6 +27,7 @@
#include <linux/netdevice.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <net/sock.h>
#include <net/sock.h>
#include <asm/uaccess.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/system.h>
...
@@ -65,8 +37,9 @@
...
@@ -65,8 +37,9 @@
#include <linux/init.h>
#include <linux/init.h>
static
ax25_route
*
ax25_route_list
;
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
* 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)
...
@@ -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
)
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
)
{
while
(
ax25_rt
!=
NULL
)
{
s
=
ax25_rt
;
s
=
ax25_rt
;
ax25_rt
=
ax25_rt
->
next
;
ax25_rt
=
ax25_rt
->
next
;
...
@@ -111,129 +86,196 @@ void ax25_rt_device_down(struct net_device *dev)
...
@@ -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
*
ax25_rt
;
ax25_route
*
s
,
*
t
,
*
ax25_rt
;
struct
ax25_routes_struct
route
;
struct
ax25_route_opt_struct
rt_option
;
ax25_dev
*
ax25_dev
;
ax25_dev
*
ax25_dev
;
int
i
;
int
i
;
switch
(
cmd
)
{
if
((
ax25_dev
=
ax25_addr_ax25dev
(
&
route
->
port_addr
))
==
NULL
)
case
SIOCADDRT
:
return
-
EINVAL
;
if
(
copy_from_user
(
&
route
,
arg
,
sizeof
(
route
)))
if
(
route
->
digi_count
>
AX25_MAX_DIGIS
)
return
-
EFAULT
;
return
-
EINVAL
;
if
((
ax25_dev
=
ax25_addr_ax25dev
(
&
route
.
port_addr
))
==
NULL
)
return
-
EINVAL
;
write_lock
(
&
ax25_route_lock
);
if
(
route
.
digi_count
>
AX25_MAX_DIGIS
)
return
-
EINVAL
;
ax25_rt
=
ax25_route_list
;
for
(
ax25_rt
=
ax25_route_list
;
ax25_rt
!=
NULL
;
ax25_rt
=
ax25_rt
->
next
)
{
while
(
ax25_rt
!=
NULL
)
{
if
(
ax25cmp
(
&
ax25_rt
->
callsign
,
&
route
.
dest_addr
)
==
0
&&
ax25_rt
->
dev
==
ax25_dev
->
dev
)
{
if
(
ax25cmp
(
&
ax25_rt
->
callsign
,
&
route
->
dest_addr
)
==
0
&&
if
(
ax25_rt
->
digipeat
!=
NULL
)
{
ax25_rt
->
dev
==
ax25_dev
->
dev
)
{
kfree
(
ax25_rt
->
digipeat
);
if
(
ax25_rt
->
digipeat
!=
NULL
)
{
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
)
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
->
repeated
[
i
]
=
0
;
ax25_rt
->
digipeat
->
calls
[
i
]
=
route
.
digi_addr
[
i
];
}
}
return
0
;
}
}
}
if
((
ax25_rt
=
kmalloc
(
sizeof
(
ax25_route
),
GFP_ATOMIC
))
==
NULL
)
if
(
route
->
digi_count
!=
0
)
{
return
-
ENOMEM
;
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
((
ax25_rt
->
digipeat
=
kmalloc
(
sizeof
(
ax25_digi
),
GFP_ATOMIC
))
==
NULL
)
{
if
((
ax25_rt
->
digipeat
=
kmalloc
(
sizeof
(
ax25_digi
),
GFP_ATOMIC
))
==
NULL
)
{
kfree
(
ax25_rt
);
write_unlock
(
&
ax25_route_lock
);
return
-
ENOMEM
;
return
-
ENOMEM
;
}
}
ax25_rt
->
digipeat
->
lastrepeat
=
-
1
;
ax25_rt
->
digipeat
->
lastrepeat
=
-
1
;
ax25_rt
->
digipeat
->
ndigi
=
route
.
digi_count
;
ax25_rt
->
digipeat
->
ndigi
=
route
->
digi_count
;
for
(
i
=
0
;
i
<
route
.
digi_count
;
i
++
)
{
for
(
i
=
0
;
i
<
route
->
digi_count
;
i
++
)
{
ax25_rt
->
digipeat
->
repeated
[
i
]
=
0
;
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
();
return
0
;
ax25_rt
->
next
=
ax25_route_list
;
}
ax25_route_list
=
ax25_rt
;
ax25_rt
=
ax25_rt
->
next
;
restore_flags
(
flags
);
}
break
;
case
SIOCDELRT
:
if
((
ax25_rt
=
kmalloc
(
sizeof
(
ax25_route
),
GFP_ATOMIC
))
==
NULL
)
{
if
(
copy_from_user
(
&
route
,
arg
,
sizeof
(
route
)))
write_unlock
(
&
ax25_route_lock
);
return
-
EFAULT
;
return
-
ENOMEM
;
if
((
ax25_dev
=
ax25_addr_ax25dev
(
&
route
.
port_addr
))
==
NULL
)
}
return
-
EINVAL
;
ax25_rt
=
ax25_route_list
;
atomic_set
(
&
ax25_rt
->
ref
,
0
);
while
(
ax25_rt
!=
NULL
)
{
ax25_rt
->
callsign
=
route
->
dest_addr
;
s
=
ax25_rt
;
ax25_rt
->
dev
=
ax25_dev
->
dev
;
ax25_rt
=
ax25_rt
->
next
;
ax25_rt
->
digipeat
=
NULL
;
if
(
s
->
dev
==
ax25_dev
->
dev
&&
ax25cmp
(
&
route
.
dest_addr
,
&
s
->
callsign
)
==
0
)
{
ax25_rt
->
ip_mode
=
' '
;
if
(
ax25_route_list
==
s
)
{
if
(
route
->
digi_count
!=
0
)
{
ax25_route_list
=
s
->
next
;
if
((
ax25_rt
->
digipeat
=
kmalloc
(
sizeof
(
ax25_digi
),
GFP_ATOMIC
))
==
NULL
)
{
if
(
s
->
digipeat
!=
NULL
)
write_unlock
(
&
ax25_route_lock
);
kfree
(
s
->
digipeat
);
kfree
(
ax25_rt
);
kfree
(
s
);
return
-
ENOMEM
;
}
else
{
}
for
(
t
=
ax25_route_list
;
t
!=
NULL
;
t
=
t
->
next
)
{
ax25_rt
->
digipeat
->
lastrepeat
=
-
1
;
if
(
t
->
next
==
s
)
{
ax25_rt
->
digipeat
->
ndigi
=
route
->
digi_count
;
t
->
next
=
s
->
next
;
for
(
i
=
0
;
i
<
route
->
digi_count
;
i
++
)
{
if
(
s
->
digipeat
!=
NULL
)
ax25_rt
->
digipeat
->
repeated
[
i
]
=
0
;
kfree
(
s
->
digipeat
);
ax25_rt
->
digipeat
->
calls
[
i
]
=
route
->
digi_addr
[
i
];
kfree
(
s
);
}
break
;
}
}
ax25_rt
->
next
=
ax25_route_list
;
}
ax25_route_list
=
ax25_rt
;
write_unlock
(
&
ax25_route_lock
);
return
0
;
}
static
int
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
(
ax25_route_list
==
s
)
{
ax25_route_list
=
s
->
next
;
ax25_rt_destroy
(
s
);
}
else
{
for
(
t
=
ax25_route_list
;
t
!=
NULL
;
t
=
t
->
next
)
{
if
(
t
->
next
==
s
)
{
t
->
next
=
s
->
next
;
ax25_rt_destroy
(
s
);
break
;
}
}
}
}
}
}
break
;
}
}
write_unlock
(
&
ax25_route_lock
);
case
SIOCAX25OPTRT
:
return
0
;
if
(
copy_from_user
(
&
rt_option
,
arg
,
sizeof
(
rt_option
)))
}
return
-
EFAULT
;
if
((
ax25_dev
=
ax25_addr_ax25dev
(
&
rt_option
.
port_addr
))
==
NULL
)
static
int
ax25_rt_opt
(
struct
ax25_route_opt_struct
*
rt_option
)
return
-
EINVAL
;
{
for
(
ax25_rt
=
ax25_route_list
;
ax25_rt
!=
NULL
;
ax25_rt
=
ax25_rt
->
next
)
{
ax25_route
*
ax25_rt
;
if
(
ax25_rt
->
dev
==
ax25_dev
->
dev
&&
ax25cmp
(
&
rt_option
.
dest_addr
,
&
ax25_rt
->
callsign
)
==
0
)
{
ax25_dev
*
ax25_dev
;
switch
(
rt_option
.
cmd
)
{
int
err
=
0
;
case
AX25_SET_RT_IPMODE
:
switch
(
rt_option
.
arg
)
{
if
((
ax25_dev
=
ax25_addr_ax25dev
(
&
rt_option
->
port_addr
))
==
NULL
)
case
' '
:
return
-
EINVAL
;
case
'D'
:
case
'V'
:
write_lock
(
&
ax25_route_lock
);
ax25_rt
->
ip_mode
=
rt_option
.
arg
;
break
;
ax25_rt
=
ax25_route_list
;
default:
while
(
ax25_rt
!=
NULL
)
{
return
-
EINVAL
;
if
(
ax25_rt
->
dev
==
ax25_dev
->
dev
&&
}
ax25cmp
(
&
rt_option
->
dest_addr
,
&
ax25_rt
->
callsign
)
==
0
)
{
break
;
switch
(
rt_option
->
cmd
)
{
default:
case
AX25_SET_RT_IPMODE
:
return
-
EINVAL
;
switch
(
rt_option
->
arg
)
{
}
case
' '
:
case
'D'
:
case
'V'
:
ax25_rt
->
ip_mode
=
rt_option
->
arg
;
break
;
default:
err
=
-
EINVAL
;
goto
out
;
}
}
break
;
default:
err
=
-
EINVAL
;
goto
out
;
}
}
break
;
}
ax25_rt
=
ax25_rt
->
next
;
default:
return
-
EINVAL
;
}
}
return
0
;
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
;
}
}
}
int
ax25_rt_get_info
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
int
ax25_rt_get_info
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
...
@@ -244,8 +286,8 @@ int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -244,8 +286,8 @@ int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
off_t
begin
=
0
;
off_t
begin
=
0
;
char
*
callsign
;
char
*
callsign
;
int
i
;
int
i
;
cli
(
);
read_lock
(
&
ax25_route_lock
);
len
+=
sprintf
(
buffer
,
"callsign dev mode digipeaters
\n
"
);
len
+=
sprintf
(
buffer
,
"callsign dev mode digipeaters
\n
"
);
...
@@ -259,15 +301,15 @@ int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -259,15 +301,15 @@ int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
ax25_rt
->
dev
?
ax25_rt
->
dev
->
name
:
"???"
);
ax25_rt
->
dev
?
ax25_rt
->
dev
->
name
:
"???"
);
switch
(
ax25_rt
->
ip_mode
)
{
switch
(
ax25_rt
->
ip_mode
)
{
case
'V'
:
case
'V'
:
len
+=
sprintf
(
buffer
+
len
,
" vc"
);
len
+=
sprintf
(
buffer
+
len
,
" vc"
);
break
;
break
;
case
'D'
:
case
'D'
:
len
+=
sprintf
(
buffer
+
len
,
" dg"
);
len
+=
sprintf
(
buffer
+
len
,
" dg"
);
break
;
break
;
default:
default:
len
+=
sprintf
(
buffer
+
len
,
" *"
);
len
+=
sprintf
(
buffer
+
len
,
" *"
);
break
;
break
;
}
}
if
(
ax25_rt
->
digipeat
!=
NULL
)
if
(
ax25_rt
->
digipeat
!=
NULL
)
...
@@ -286,26 +328,29 @@ int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -286,26 +328,29 @@ int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
if
(
pos
>
offset
+
length
)
if
(
pos
>
offset
+
length
)
break
;
break
;
}
}
read_unlock
(
&
ax25_route_lock
);
sti
();
*
start
=
buffer
+
(
offset
-
begin
);
*
start
=
buffer
+
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
if
(
len
>
length
)
len
=
length
;
if
(
len
>
length
)
len
=
length
;
return
len
;
return
len
;
}
}
/*
/*
* Find AX.25 route
* 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_spe_rt
=
NULL
;
ax25_route
*
ax25_def_rt
=
NULL
;
ax25_route
*
ax25_def_rt
=
NULL
;
ax25_route
*
ax25_rt
;
ax25_route
*
ax25_rt
;
read_lock
(
&
ax25_route_lock
);
/*
/*
* Bind to the physical interface we heard them on, or the default
* Bind to the physical interface we heard them on, or the default
* route if none is found;
* route if none is found;
...
@@ -324,10 +369,16 @@ static ax25_route *ax25_find_route(ax25_address *addr, struct net_device *dev)
...
@@ -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
)
if
(
ax25_spe_rt
!=
NULL
)
return
ax25_spe_rt
;
ax25_rt
=
ax25_spe_rt
;
return
ax25_def_rt
;
if
(
ax25_rt
!=
NULL
)
atomic_inc
(
&
ax25_rt
->
ref
);
read_unlock
(
&
ax25_route_lock
);
return
ax25_rt
;
}
}
/*
/*
...
@@ -346,7 +397,7 @@ static inline void ax25_adjust_path(ax25_address *addr, ax25_digi *digipeat)
...
@@ -346,7 +397,7 @@ static inline void ax25_adjust_path(ax25_address *addr, ax25_digi *digipeat)
digipeat
->
ndigi
=
k
;
digipeat
->
ndigi
=
k
;
}
}
/*
/*
* Find which interface to use.
* Find which interface to use.
...
@@ -355,24 +406,31 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
...
@@ -355,24 +406,31 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
{
{
ax25_route
*
ax25_rt
;
ax25_route
*
ax25_rt
;
ax25_address
*
call
;
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
;
return
-
EHOSTUNREACH
;
if
((
ax25
->
ax25_dev
=
ax25_dev_ax25dev
(
ax25_rt
->
dev
))
==
NULL
)
if
((
ax25
->
ax25_dev
=
ax25_dev_ax25dev
(
ax25_rt
->
dev
))
==
NULL
)
{
return
-
EHOSTUNREACH
;
err
=
-
EHOSTUNREACH
;
goto
put
;
}
if
((
call
=
ax25_findbyuid
(
current
->
euid
))
==
NULL
)
{
if
((
call
=
ax25_findbyuid
(
current
->
euid
))
==
NULL
)
{
if
(
ax25_uid_policy
&&
!
capable
(
CAP_NET_BIND_SERVICE
))
if
(
ax25_uid_policy
&&
!
capable
(
CAP_NET_BIND_SERVICE
))
{
return
-
EPERM
;
err
=
-
EPERM
;
goto
put
;
}
call
=
(
ax25_address
*
)
ax25
->
ax25_dev
->
dev
->
dev_addr
;
call
=
(
ax25_address
*
)
ax25
->
ax25_dev
->
dev
->
dev_addr
;
}
}
ax25
->
source_addr
=
*
call
;
ax25
->
source_addr
=
*
call
;
if
(
ax25_rt
->
digipeat
!=
NULL
)
{
if
(
ax25_rt
->
digipeat
!=
NULL
)
{
if
((
ax25
->
digipeat
=
kmalloc
(
sizeof
(
ax25_digi
),
GFP_ATOMIC
))
==
NULL
)
if
((
ax25
->
digipeat
=
kmalloc
(
sizeof
(
ax25_digi
),
GFP_ATOMIC
))
==
NULL
)
{
return
-
ENOMEM
;
err
=
-
ENOMEM
;
goto
put
;
}
memcpy
(
ax25
->
digipeat
,
ax25_rt
->
digipeat
,
sizeof
(
ax25_digi
));
memcpy
(
ax25
->
digipeat
,
ax25_rt
->
digipeat
,
sizeof
(
ax25_digi
));
ax25_adjust_path
(
addr
,
ax25
->
digipeat
);
ax25_adjust_path
(
addr
,
ax25
->
digipeat
);
}
}
...
@@ -380,31 +438,32 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
...
@@ -380,31 +438,32 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
if
(
ax25
->
sk
!=
NULL
)
if
(
ax25
->
sk
!=
NULL
)
ax25
->
sk
->
zapped
=
0
;
ax25
->
sk
->
zapped
=
0
;
put:
ax25_put_route
(
ax25_rt
);
return
0
;
return
0
;
}
}
/*
ax25_route
*
ax25_rt_find_route
(
ax25_route
*
route
,
ax25_address
*
addr
,
* dl1bke 960117: build digipeater path
struct
net_device
*
dev
)
* dl1bke 960301: use the default route if it exists
*/
ax25_route
*
ax25_rt_find_route
(
ax25_address
*
addr
,
struct
net_device
*
dev
)
{
{
static
ax25_route
route
;
ax25_route
*
ax25_rt
;
ax25_route
*
ax25_rt
;
if
((
ax25_rt
=
ax25_find_route
(
addr
,
dev
))
==
NULL
)
{
if
((
ax25_rt
=
ax25_get_route
(
addr
,
dev
)))
route
.
next
=
NULL
;
return
ax25_rt
;
route
.
callsign
=
*
addr
;
route
.
dev
=
dev
;
route
.
digipeat
=
NULL
;
route
.
ip_mode
=
' '
;
return
&
route
;
}
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
;
struct
sk_buff
*
skbn
;
unsigned
char
*
bp
;
unsigned
char
*
bp
;
...
@@ -440,6 +499,7 @@ void __exit ax25_rt_free(void)
...
@@ -440,6 +499,7 @@ void __exit ax25_rt_free(void)
{
{
ax25_route
*
s
,
*
ax25_rt
=
ax25_route_list
;
ax25_route
*
s
,
*
ax25_rt
=
ax25_route_list
;
write_unlock
(
&
ax25_route_lock
);
while
(
ax25_rt
!=
NULL
)
{
while
(
ax25_rt
!=
NULL
)
{
s
=
ax25_rt
;
s
=
ax25_rt
;
ax25_rt
=
ax25_rt
->
next
;
ax25_rt
=
ax25_rt
->
next
;
...
@@ -449,4 +509,5 @@ void __exit ax25_rt_free(void)
...
@@ -449,4 +509,5 @@ void __exit ax25_rt_free(void)
kfree
(
s
);
kfree
(
s
);
}
}
write_unlock
(
&
ax25_route_lock
);
}
}
net/ax25/ax25_std_in.c
View file @
b331768e
/*
/*
* 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:
* Most of this code is based on the SDL diagrams published in the 7th ARRL
* This module is free software; you can redistribute it and/or
* Computer Networking Conference papers. The diagrams have mistakes in them,
* modify it under the terms of the GNU General Public License
* but are mostly correct. Before you modify the code could you read the SDL
* as published by the Free Software Foundation; either version
* diagrams as the code is not obvious and probably very easy to break.
* 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.
*/
*/
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
...
@@ -68,55 +45,55 @@
...
@@ -68,55 +45,55 @@
static
int
ax25_std_state1_machine
(
ax25_cb
*
ax25
,
struct
sk_buff
*
skb
,
int
frametype
,
int
pf
,
int
type
)
static
int
ax25_std_state1_machine
(
ax25_cb
*
ax25
,
struct
sk_buff
*
skb
,
int
frametype
,
int
pf
,
int
type
)
{
{
switch
(
frametype
)
{
switch
(
frametype
)
{
case
AX25_SABM
:
case
AX25_SABM
:
ax25
->
modulus
=
AX25_MODULUS
;
ax25
->
modulus
=
AX25_MODULUS
;
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_WINDOW
];
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_WINDOW
];
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
break
;
break
;
case
AX25_SABME
:
case
AX25_SABME
:
ax25
->
modulus
=
AX25_EMODULUS
;
ax25
->
modulus
=
AX25_EMODULUS
;
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_EWINDOW
];
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_EWINDOW
];
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
break
;
break
;
case
AX25_DISC
:
case
AX25_DISC
:
ax25_send_control
(
ax25
,
AX25_DM
,
pf
,
AX25_RESPONSE
);
ax25_send_control
(
ax25
,
AX25_DM
,
pf
,
AX25_RESPONSE
);
break
;
break
;
case
AX25_UA
:
case
AX25_UA
:
if
(
pf
)
{
if
(
pf
)
{
ax25_calculate_rtt
(
ax25
);
ax25_calculate_rtt
(
ax25
);
ax25_stop_t1timer
(
ax25
);
ax25_stop_t1timer
(
ax25
);
ax25_start_t3timer
(
ax25
);
ax25_start_t3timer
(
ax25
);
ax25_start_idletimer
(
ax25
);
ax25_start_idletimer
(
ax25
);
ax25
->
vs
=
0
;
ax25
->
vs
=
0
;
ax25
->
va
=
0
;
ax25
->
va
=
0
;
ax25
->
vr
=
0
;
ax25
->
vr
=
0
;
ax25
->
state
=
AX25_STATE_3
;
ax25
->
state
=
AX25_STATE_3
;
ax25
->
n2count
=
0
;
ax25
->
n2count
=
0
;
if
(
ax25
->
sk
!=
NULL
)
{
if
(
ax25
->
sk
!=
NULL
)
{
ax25
->
sk
->
state
=
TCP_ESTABLISHED
;
ax25
->
sk
->
state
=
TCP_ESTABLISHED
;
/* For WAIT_SABM connections we will produce an accept ready socket here */
/* For WAIT_SABM connections we will produce an accept ready socket here */
if
(
!
ax25
->
sk
->
dead
)
if
(
!
ax25
->
sk
->
dead
)
ax25
->
sk
->
state_change
(
ax25
->
sk
);
ax25
->
sk
->
state_change
(
ax25
->
sk
);
}
}
}
break
;
}
break
;
case
AX25_DM
:
case
AX25_DM
:
if
(
pf
)
{
if
(
pf
)
{
if
(
ax25
->
modulus
==
AX25_MODULUS
)
{
if
(
ax25
->
modulus
==
AX25_MODULUS
)
{
ax25_disconnect
(
ax25
,
ECONNREFUSED
);
ax25_disconnect
(
ax25
,
ECONNREFUSED
);
}
else
{
}
else
{
ax25
->
modulus
=
AX25_MODULUS
;
ax25
->
modulus
=
AX25_MODULUS
;
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_WINDOW
];
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_WINDOW
];
}
}
}
break
;
}
break
;
default:
default:
break
;
break
;
}
}
return
0
;
return
0
;
...
@@ -130,30 +107,31 @@ static int ax25_std_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
...
@@ -130,30 +107,31 @@ static int ax25_std_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
static
int
ax25_std_state2_machine
(
ax25_cb
*
ax25
,
struct
sk_buff
*
skb
,
int
frametype
,
int
pf
,
int
type
)
static
int
ax25_std_state2_machine
(
ax25_cb
*
ax25
,
struct
sk_buff
*
skb
,
int
frametype
,
int
pf
,
int
type
)
{
{
switch
(
frametype
)
{
switch
(
frametype
)
{
case
AX25_SABM
:
case
AX25_SABM
:
case
AX25_SABME
:
case
AX25_SABME
:
ax25_send_control
(
ax25
,
AX25_DM
,
pf
,
AX25_RESPONSE
);
ax25_send_control
(
ax25
,
AX25_DM
,
pf
,
AX25_RESPONSE
);
break
;
break
;
case
AX25_DISC
:
case
AX25_DISC
:
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
ax25_disconnect
(
ax25
,
0
);
break
;
case
AX25_DM
:
case
AX25_UA
:
if
(
pf
)
ax25_disconnect
(
ax25
,
0
);
ax25_disconnect
(
ax25
,
0
);
break
;
break
;
case
AX25_DM
:
case
AX25_I
:
case
AX25_UA
:
case
AX25_REJ
:
if
(
pf
)
ax25_disconnect
(
ax25
,
0
);
case
AX25_RNR
:
break
;
case
AX25_RR
:
if
(
pf
)
ax25_send_control
(
ax25
,
AX25_DM
,
AX25_POLLON
,
AX25_RESPONSE
);
case
AX25_I
:
break
;
case
AX25_REJ
:
case
AX25_RNR
:
case
AX25_RR
:
if
(
pf
)
ax25_send_control
(
ax25
,
AX25_DM
,
AX25_POLLON
,
AX25_RESPONSE
);
break
;
default:
default:
break
;
break
;
}
}
return
0
;
return
0
;
...
@@ -169,116 +147,116 @@ static int ax25_std_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
...
@@ -169,116 +147,116 @@ static int ax25_std_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
int
queued
=
0
;
int
queued
=
0
;
switch
(
frametype
)
{
switch
(
frametype
)
{
case
AX25_SABM
:
case
AX25_SABM
:
case
AX25_SABME
:
case
AX25_SABME
:
if
(
frametype
==
AX25_SABM
)
{
if
(
frametype
==
AX25_SABM
)
{
ax25
->
modulus
=
AX25_MODULUS
;
ax25
->
modulus
=
AX25_MODULUS
;
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_WINDOW
];
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_WINDOW
];
}
else
{
}
else
{
ax25
->
modulus
=
AX25_EMODULUS
;
ax25
->
modulus
=
AX25_EMODULUS
;
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_EWINDOW
];
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_EWINDOW
];
}
}
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
ax25_stop_t1timer
(
ax25
);
ax25_stop_t2timer
(
ax25
);
ax25_start_t3timer
(
ax25
);
ax25_start_idletimer
(
ax25
);
ax25
->
condition
=
0x00
;
ax25
->
vs
=
0
;
ax25
->
va
=
0
;
ax25
->
vr
=
0
;
ax25_requeue_frames
(
ax25
);
break
;
case
AX25_DISC
:
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
ax25_disconnect
(
ax25
,
0
);
break
;
case
AX25_DM
:
ax25_disconnect
(
ax25
,
ECONNRESET
);
break
;
case
AX25_RR
:
case
AX25_RNR
:
if
(
frametype
==
AX25_RR
)
ax25
->
condition
&=
~
AX25_COND_PEER_RX_BUSY
;
else
ax25
->
condition
|=
AX25_COND_PEER_RX_BUSY
;
if
(
type
==
AX25_COMMAND
&&
pf
)
ax25_std_enquiry_response
(
ax25
);
if
(
ax25_validate_nr
(
ax25
,
nr
))
{
ax25_check_iframes_acked
(
ax25
,
nr
);
}
else
{
ax25_std_nr_error_recovery
(
ax25
);
ax25
->
state
=
AX25_STATE_1
;
}
break
;
case
AX25_REJ
:
ax25
->
condition
&=
~
AX25_COND_PEER_RX_BUSY
;
if
(
type
==
AX25_COMMAND
&&
pf
)
ax25_std_enquiry_response
(
ax25
);
if
(
ax25_validate_nr
(
ax25
,
nr
))
{
ax25_frames_acked
(
ax25
,
nr
);
ax25_calculate_rtt
(
ax25
);
ax25_stop_t1timer
(
ax25
);
ax25_stop_t1timer
(
ax25
);
ax25_stop_t2timer
(
ax25
);
ax25_start_t3timer
(
ax25
);
ax25_start_t3timer
(
ax25
);
ax25_start_idletimer
(
ax25
);
ax25
->
condition
=
0x00
;
ax25
->
vs
=
0
;
ax25
->
va
=
0
;
ax25
->
vr
=
0
;
ax25_requeue_frames
(
ax25
);
ax25_requeue_frames
(
ax25
);
break
;
}
else
{
ax25_std_nr_error_recovery
(
ax25
);
case
AX25_DISC
:
ax25
->
state
=
AX25_STATE_1
;
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
}
ax25_disconnect
(
ax25
,
0
);
break
;
break
;
case
AX25_DM
:
case
AX25_I
:
ax25_disconnect
(
ax25
,
ECONNRESET
);
if
(
!
ax25_validate_nr
(
ax25
,
nr
))
{
ax25_std_nr_error_recovery
(
ax25
);
ax25
->
state
=
AX25_STATE_1
;
break
;
break
;
}
case
AX25_RR
:
if
(
ax25
->
condition
&
AX25_COND_PEER_RX_BUSY
)
{
case
AX25_RNR
:
ax25_frames_acked
(
ax25
,
nr
);
if
(
frametype
==
AX25_RR
)
}
else
{
ax25
->
condition
&=
~
AX25_COND_PEER_RX_BUSY
;
ax25_check_iframes_acked
(
ax25
,
nr
);
else
}
ax25
->
condition
|=
AX25_COND_PEER_RX_BUSY
;
if
(
ax25
->
condition
&
AX25_COND_OWN_RX_BUSY
)
{
if
(
type
==
AX25_COMMAND
&&
pf
)
if
(
pf
)
ax25_std_enquiry_response
(
ax25
);
ax25_std_enquiry_response
(
ax25
);
if
(
ax25_validate_nr
(
ax25
,
nr
))
{
ax25_check_iframes_acked
(
ax25
,
nr
);
}
else
{
ax25_std_nr_error_recovery
(
ax25
);
ax25
->
state
=
AX25_STATE_1
;
}
break
;
break
;
}
case
AX25_REJ
:
if
(
ns
==
ax25
->
vr
)
{
ax25
->
condition
&=
~
AX25_COND_PEER_RX_BUSY
;
ax25
->
vr
=
(
ax25
->
vr
+
1
)
%
ax25
->
modulus
;
if
(
type
==
AX25_COMMAND
&&
pf
)
queued
=
ax25_rx_iframe
(
ax25
,
skb
);
if
(
ax25
->
condition
&
AX25_COND_OWN_RX_BUSY
)
ax25
->
vr
=
ns
;
/* ax25->vr - 1 */
ax25
->
condition
&=
~
AX25_COND_REJECT
;
if
(
pf
)
{
ax25_std_enquiry_response
(
ax25
);
ax25_std_enquiry_response
(
ax25
);
if
(
ax25_validate_nr
(
ax25
,
nr
))
{
ax25_frames_acked
(
ax25
,
nr
);
ax25_calculate_rtt
(
ax25
);
ax25_stop_t1timer
(
ax25
);
ax25_start_t3timer
(
ax25
);
ax25_requeue_frames
(
ax25
);
}
else
{
}
else
{
ax25_std_nr_error_recovery
(
ax25
);
if
(
!
(
ax25
->
condition
&
AX25_COND_ACK_PENDING
))
{
ax25
->
state
=
AX25_STATE_1
;
ax25
->
condition
|=
AX25_COND_ACK_PENDING
;
}
ax25_start_t2timer
(
ax25
);
break
;
}
case
AX25_I
:
if
(
!
ax25_validate_nr
(
ax25
,
nr
))
{
ax25_std_nr_error_recovery
(
ax25
);
ax25
->
state
=
AX25_STATE_1
;
break
;
}
if
(
ax25
->
condition
&
AX25_COND_PEER_RX_BUSY
)
{
ax25_frames_acked
(
ax25
,
nr
);
}
else
{
ax25_check_iframes_acked
(
ax25
,
nr
);
}
}
if
(
ax25
->
condition
&
AX25_COND_OWN_RX_BUSY
)
{
}
else
{
if
(
ax25
->
condition
&
AX25_COND_REJECT
)
{
if
(
pf
)
ax25_std_enquiry_response
(
ax25
);
if
(
pf
)
ax25_std_enquiry_response
(
ax25
);
break
;
}
if
(
ns
==
ax25
->
vr
)
{
ax25
->
vr
=
(
ax25
->
vr
+
1
)
%
ax25
->
modulus
;
queued
=
ax25_rx_iframe
(
ax25
,
skb
);
if
(
ax25
->
condition
&
AX25_COND_OWN_RX_BUSY
)
ax25
->
vr
=
ns
;
/* ax25->vr - 1 */
ax25
->
condition
&=
~
AX25_COND_REJECT
;
if
(
pf
)
{
ax25_std_enquiry_response
(
ax25
);
}
else
{
if
(
!
(
ax25
->
condition
&
AX25_COND_ACK_PENDING
))
{
ax25
->
condition
|=
AX25_COND_ACK_PENDING
;
ax25_start_t2timer
(
ax25
);
}
}
}
else
{
}
else
{
if
(
ax25
->
condition
&
AX25_COND_REJECT
)
{
ax25
->
condition
|=
AX25_COND_REJECT
;
if
(
pf
)
ax25_std_enquiry_response
(
ax25
);
ax25_send_control
(
ax25
,
AX25_REJ
,
pf
,
AX25_RESPONSE
);
}
else
{
ax25
->
condition
&=
~
AX25_COND_ACK_PENDING
;
ax25
->
condition
|=
AX25_COND_REJECT
;
ax25_send_control
(
ax25
,
AX25_REJ
,
pf
,
AX25_RESPONSE
);
ax25
->
condition
&=
~
AX25_COND_ACK_PENDING
;
}
}
}
break
;
}
break
;
case
AX25_FRMR
:
case
AX25_FRMR
:
case
AX25_ILLEGAL
:
case
AX25_ILLEGAL
:
ax25_std_establish_data_link
(
ax25
);
ax25_std_establish_data_link
(
ax25
);
ax25
->
state
=
AX25_STATE_1
;
ax25
->
state
=
AX25_STATE_1
;
break
;
break
;
default:
default:
break
;
break
;
}
}
return
queued
;
return
queued
;
...
@@ -294,145 +272,146 @@ static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
...
@@ -294,145 +272,146 @@ static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
int
queued
=
0
;
int
queued
=
0
;
switch
(
frametype
)
{
switch
(
frametype
)
{
case
AX25_SABM
:
case
AX25_SABM
:
case
AX25_SABME
:
case
AX25_SABME
:
if
(
frametype
==
AX25_SABM
)
{
if
(
frametype
==
AX25_SABM
)
{
ax25
->
modulus
=
AX25_MODULUS
;
ax25
->
modulus
=
AX25_MODULUS
;
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_WINDOW
];
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_WINDOW
];
}
else
{
}
else
{
ax25
->
modulus
=
AX25_EMODULUS
;
ax25
->
modulus
=
AX25_EMODULUS
;
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_EWINDOW
];
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_EWINDOW
];
}
}
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
ax25_stop_t1timer
(
ax25
);
ax25_stop_t2timer
(
ax25
);
ax25_start_t3timer
(
ax25
);
ax25_start_idletimer
(
ax25
);
ax25
->
condition
=
0x00
;
ax25
->
vs
=
0
;
ax25
->
va
=
0
;
ax25
->
vr
=
0
;
ax25
->
state
=
AX25_STATE_3
;
ax25
->
n2count
=
0
;
ax25_requeue_frames
(
ax25
);
break
;
case
AX25_DISC
:
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
ax25_disconnect
(
ax25
,
0
);
break
;
case
AX25_DM
:
ax25_disconnect
(
ax25
,
ECONNRESET
);
break
;
case
AX25_RR
:
case
AX25_RNR
:
if
(
frametype
==
AX25_RR
)
ax25
->
condition
&=
~
AX25_COND_PEER_RX_BUSY
;
else
ax25
->
condition
|=
AX25_COND_PEER_RX_BUSY
;
if
(
type
==
AX25_RESPONSE
&&
pf
)
{
ax25_stop_t1timer
(
ax25
);
ax25_stop_t1timer
(
ax25
);
ax25_stop_t2timer
(
ax25
);
ax25
->
n2count
=
0
;
ax25_start_t3timer
(
ax25
);
ax25_start_idletimer
(
ax25
);
ax25
->
condition
=
0x00
;
ax25
->
vs
=
0
;
ax25
->
va
=
0
;
ax25
->
vr
=
0
;
ax25
->
state
=
AX25_STATE_3
;
ax25
->
n2count
=
0
;
ax25_requeue_frames
(
ax25
);
break
;
case
AX25_DISC
:
ax25_send_control
(
ax25
,
AX25_UA
,
pf
,
AX25_RESPONSE
);
ax25_disconnect
(
ax25
,
0
);
break
;
case
AX25_DM
:
ax25_disconnect
(
ax25
,
ECONNRESET
);
break
;
case
AX25_RR
:
case
AX25_RNR
:
if
(
frametype
==
AX25_RR
)
ax25
->
condition
&=
~
AX25_COND_PEER_RX_BUSY
;
else
ax25
->
condition
|=
AX25_COND_PEER_RX_BUSY
;
if
(
type
==
AX25_RESPONSE
&&
pf
)
{
ax25_stop_t1timer
(
ax25
);
ax25
->
n2count
=
0
;
if
(
ax25_validate_nr
(
ax25
,
nr
))
{
ax25_frames_acked
(
ax25
,
nr
);
if
(
ax25
->
vs
==
ax25
->
va
)
{
ax25_start_t3timer
(
ax25
);
ax25
->
state
=
AX25_STATE_3
;
}
else
{
ax25_requeue_frames
(
ax25
);
}
}
else
{
ax25_std_nr_error_recovery
(
ax25
);
ax25
->
state
=
AX25_STATE_1
;
}
break
;
}
if
(
type
==
AX25_COMMAND
&&
pf
)
ax25_std_enquiry_response
(
ax25
);
if
(
ax25_validate_nr
(
ax25
,
nr
))
{
if
(
ax25_validate_nr
(
ax25
,
nr
))
{
ax25_frames_acked
(
ax25
,
nr
);
ax25_frames_acked
(
ax25
,
nr
);
if
(
ax25
->
vs
==
ax25
->
va
)
{
ax25_start_t3timer
(
ax25
);
ax25
->
state
=
AX25_STATE_3
;
}
else
{
ax25_requeue_frames
(
ax25
);
}
}
else
{
}
else
{
ax25_std_nr_error_recovery
(
ax25
);
ax25_std_nr_error_recovery
(
ax25
);
ax25
->
state
=
AX25_STATE_1
;
ax25
->
state
=
AX25_STATE_1
;
}
}
break
;
break
;
}
if
(
type
==
AX25_COMMAND
&&
pf
)
ax25_std_enquiry_response
(
ax25
);
if
(
ax25_validate_nr
(
ax25
,
nr
))
{
ax25_frames_acked
(
ax25
,
nr
);
}
else
{
ax25_std_nr_error_recovery
(
ax25
);
ax25
->
state
=
AX25_STATE_1
;
}
break
;
case
AX25_REJ
:
case
AX25_REJ
:
ax25
->
condition
&=
~
AX25_COND_PEER_RX_BUSY
;
ax25
->
condition
&=
~
AX25_COND_PEER_RX_BUSY
;
if
(
pf
&&
type
==
AX25_RESPONSE
)
{
if
(
pf
&&
type
==
AX25_RESPONSE
)
{
ax25_stop_t1timer
(
ax25
);
ax25_stop_t1timer
(
ax25
);
ax25
->
n2count
=
0
;
ax25
->
n2count
=
0
;
if
(
ax25_validate_nr
(
ax25
,
nr
))
{
ax25_frames_acked
(
ax25
,
nr
);
if
(
ax25
->
vs
==
ax25
->
va
)
{
ax25_start_t3timer
(
ax25
);
ax25
->
state
=
AX25_STATE_3
;
}
else
{
ax25_requeue_frames
(
ax25
);
}
}
else
{
ax25_std_nr_error_recovery
(
ax25
);
ax25
->
state
=
AX25_STATE_1
;
}
break
;
}
if
(
type
==
AX25_COMMAND
&&
pf
)
ax25_std_enquiry_response
(
ax25
);
if
(
ax25_validate_nr
(
ax25
,
nr
))
{
if
(
ax25_validate_nr
(
ax25
,
nr
))
{
ax25_frames_acked
(
ax25
,
nr
);
ax25_frames_acked
(
ax25
,
nr
);
ax25_requeue_frames
(
ax25
);
if
(
ax25
->
vs
==
ax25
->
va
)
{
ax25_start_t3timer
(
ax25
);
ax25
->
state
=
AX25_STATE_3
;
}
else
{
ax25_requeue_frames
(
ax25
);
}
}
else
{
}
else
{
ax25_std_nr_error_recovery
(
ax25
);
ax25_std_nr_error_recovery
(
ax25
);
ax25
->
state
=
AX25_STATE_1
;
ax25
->
state
=
AX25_STATE_1
;
}
}
break
;
break
;
}
if
(
type
==
AX25_COMMAND
&&
pf
)
ax25_std_enquiry_response
(
ax25
);
if
(
ax25_validate_nr
(
ax25
,
nr
))
{
ax25_frames_acked
(
ax25
,
nr
);
ax25_requeue_frames
(
ax25
);
}
else
{
ax25_std_nr_error_recovery
(
ax25
);
ax25
->
state
=
AX25_STATE_1
;
}
break
;
case
AX25_I
:
case
AX25_I
:
if
(
!
ax25_validate_nr
(
ax25
,
nr
))
{
if
(
!
ax25_validate_nr
(
ax25
,
nr
))
{
ax25_std_nr_error_recovery
(
ax25
);
ax25_std_nr_error_recovery
(
ax25
);
ax25
->
state
=
AX25_STATE_1
;
ax25
->
state
=
AX25_STATE_1
;
break
;
break
;
}
ax25_frames_acked
(
ax25
,
nr
);
if
(
ax25
->
condition
&
AX25_COND_OWN_RX_BUSY
)
{
if
(
pf
)
ax25_std_enquiry_response
(
ax25
);
break
;
}
if
(
ns
==
ax25
->
vr
)
{
ax25
->
vr
=
(
ax25
->
vr
+
1
)
%
ax25
->
modulus
;
queued
=
ax25_rx_iframe
(
ax25
,
skb
);
if
(
ax25
->
condition
&
AX25_COND_OWN_RX_BUSY
)
ax25
->
vr
=
ns
;
/* ax25->vr - 1 */
ax25
->
condition
&=
~
AX25_COND_REJECT
;
if
(
pf
)
{
ax25_std_enquiry_response
(
ax25
);
}
else
{
if
(
!
(
ax25
->
condition
&
AX25_COND_ACK_PENDING
))
{
ax25
->
condition
|=
AX25_COND_ACK_PENDING
;
ax25_start_t2timer
(
ax25
);
}
}
}
ax25_frames_acked
(
ax25
,
nr
);
}
else
{
if
(
ax25
->
condition
&
AX25_COND_
OWN_RX_BUSY
)
{
if
(
ax25
->
condition
&
AX25_COND_
REJECT
)
{
if
(
pf
)
ax25_std_enquiry_response
(
ax25
);
if
(
pf
)
ax25_std_enquiry_response
(
ax25
);
break
;
}
if
(
ns
==
ax25
->
vr
)
{
ax25
->
vr
=
(
ax25
->
vr
+
1
)
%
ax25
->
modulus
;
queued
=
ax25_rx_iframe
(
ax25
,
skb
);
if
(
ax25
->
condition
&
AX25_COND_OWN_RX_BUSY
)
ax25
->
vr
=
ns
;
/* ax25->vr - 1 */
ax25
->
condition
&=
~
AX25_COND_REJECT
;
if
(
pf
)
{
ax25_std_enquiry_response
(
ax25
);
}
else
{
if
(
!
(
ax25
->
condition
&
AX25_COND_ACK_PENDING
))
{
ax25
->
condition
|=
AX25_COND_ACK_PENDING
;
ax25_start_t2timer
(
ax25
);
}
}
}
else
{
}
else
{
if
(
ax25
->
condition
&
AX25_COND_REJECT
)
{
ax25
->
condition
|=
AX25_COND_REJECT
;
if
(
pf
)
ax25_std_enquiry_response
(
ax25
);
ax25_send_control
(
ax25
,
AX25_REJ
,
pf
,
AX25_RESPONSE
);
}
else
{
ax25
->
condition
&=
~
AX25_COND_ACK_PENDING
;
ax25
->
condition
|=
AX25_COND_REJECT
;
ax25_send_control
(
ax25
,
AX25_REJ
,
pf
,
AX25_RESPONSE
);
ax25
->
condition
&=
~
AX25_COND_ACK_PENDING
;
}
}
}
break
;
}
break
;
case
AX25_FRMR
:
case
AX25_FRMR
:
case
AX25_ILLEGAL
:
case
AX25_ILLEGAL
:
ax25_std_establish_data_link
(
ax25
);
ax25_std_establish_data_link
(
ax25
);
ax25
->
state
=
AX25_STATE_1
;
ax25
->
state
=
AX25_STATE_1
;
break
;
break
;
default:
default:
break
;
break
;
}
}
return
queued
;
return
queued
;
...
@@ -448,18 +427,18 @@ int ax25_std_frame_in(ax25_cb *ax25, struct sk_buff *skb, int type)
...
@@ -448,18 +427,18 @@ int ax25_std_frame_in(ax25_cb *ax25, struct sk_buff *skb, int type)
frametype
=
ax25_decode
(
ax25
,
skb
,
&
ns
,
&
nr
,
&
pf
);
frametype
=
ax25_decode
(
ax25
,
skb
,
&
ns
,
&
nr
,
&
pf
);
switch
(
ax25
->
state
)
{
switch
(
ax25
->
state
)
{
case
AX25_STATE_1
:
case
AX25_STATE_1
:
queued
=
ax25_std_state1_machine
(
ax25
,
skb
,
frametype
,
pf
,
type
);
queued
=
ax25_std_state1_machine
(
ax25
,
skb
,
frametype
,
pf
,
type
);
break
;
break
;
case
AX25_STATE_2
:
case
AX25_STATE_2
:
queued
=
ax25_std_state2_machine
(
ax25
,
skb
,
frametype
,
pf
,
type
);
queued
=
ax25_std_state2_machine
(
ax25
,
skb
,
frametype
,
pf
,
type
);
break
;
break
;
case
AX25_STATE_3
:
case
AX25_STATE_3
:
queued
=
ax25_std_state3_machine
(
ax25
,
skb
,
frametype
,
ns
,
nr
,
pf
,
type
);
queued
=
ax25_std_state3_machine
(
ax25
,
skb
,
frametype
,
ns
,
nr
,
pf
,
type
);
break
;
break
;
case
AX25_STATE_4
:
case
AX25_STATE_4
:
queued
=
ax25_std_state4_machine
(
ax25
,
skb
,
frametype
,
ns
,
nr
,
pf
,
type
);
queued
=
ax25_std_state4_machine
(
ax25
,
skb
,
frametype
,
ns
,
nr
,
pf
,
type
);
break
;
break
;
}
}
ax25_kick
(
ax25
);
ax25_kick
(
ax25
);
...
...
net/ax25/ax25_std_subr.c
View file @
b331768e
/*
/*
* 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) 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
* AX.25 036 Jonathan(G4KLX) Split from ax25_out.c.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
*/
*/
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
...
@@ -80,7 +66,7 @@ void ax25_std_transmit_enquiry(ax25_cb *ax25)
...
@@ -80,7 +66,7 @@ void ax25_std_transmit_enquiry(ax25_cb *ax25)
ax25_calculate_t1
(
ax25
);
ax25_calculate_t1
(
ax25
);
ax25_start_t1timer
(
ax25
);
ax25_start_t1timer
(
ax25
);
}
}
void
ax25_std_enquiry_response
(
ax25_cb
*
ax25
)
void
ax25_std_enquiry_response
(
ax25_cb
*
ax25
)
{
{
if
(
ax25
->
condition
&
AX25_COND_OWN_RX_BUSY
)
if
(
ax25
->
condition
&
AX25_COND_OWN_RX_BUSY
)
...
...
net/ax25/ax25_std_timer.c
View file @
b331768e
/*
/*
* 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)
* This module:
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* This module is free software; you can redistribute it and/or
* Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
* 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.
*/
*/
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
...
@@ -47,30 +34,29 @@
...
@@ -47,30 +34,29 @@
void
ax25_std_heartbeat_expiry
(
ax25_cb
*
ax25
)
void
ax25_std_heartbeat_expiry
(
ax25_cb
*
ax25
)
{
{
switch
(
ax25
->
state
)
{
switch
(
ax25
->
state
)
{
case
AX25_STATE_0
:
case
AX25_STATE_0
:
/* Magic here: If we listen() and a new link dies before it
/* Magic here: If we listen() and a new link dies before it
is accepted() it isn't 'dead' so doesn't get removed. */
is accepted() it isn't 'dead' so doesn't get removed. */
if
(
ax25
->
sk
==
NULL
||
ax25
->
sk
->
destroy
||
(
ax25
->
sk
->
state
==
TCP_LISTEN
&&
ax25
->
sk
->
dead
))
{
if
(
ax25
->
sk
==
NULL
||
ax25
->
sk
->
destroy
||
(
ax25
->
sk
->
state
==
TCP_LISTEN
&&
ax25
->
sk
->
dead
))
{
ax25_destroy_socket
(
ax25
);
ax25_destroy_socket
(
ax25
);
return
;
return
;
}
}
break
;
break
;
case
AX25_STATE_3
:
case
AX25_STATE_3
:
case
AX25_STATE_4
:
case
AX25_STATE_4
:
/*
/*
* Check the state of the receive buffer.
* Check the state of the receive buffer.
*/
*/
if
(
ax25
->
sk
!=
NULL
)
{
if
(
ax25
->
sk
!=
NULL
)
{
if
(
atomic_read
(
&
ax25
->
sk
->
rmem_alloc
)
<
(
ax25
->
sk
->
rcvbuf
/
2
)
&&
if
(
atomic_read
(
&
ax25
->
sk
->
rmem_alloc
)
<
(
ax25
->
sk
->
rcvbuf
/
2
)
&&
(
ax25
->
condition
&
AX25_COND_OWN_RX_BUSY
))
{
(
ax25
->
condition
&
AX25_COND_OWN_RX_BUSY
))
{
ax25
->
condition
&=
~
AX25_COND_OWN_RX_BUSY
;
ax25
->
condition
&=
~
AX25_COND_OWN_RX_BUSY
;
ax25
->
condition
&=
~
AX25_COND_ACK_PENDING
;
ax25
->
condition
&=
~
AX25_COND_ACK_PENDING
;
ax25_send_control
(
ax25
,
AX25_RR
,
AX25_POLLOFF
,
AX25_RESPONSE
);
ax25_send_control
(
ax25
,
AX25_RR
,
AX25_POLLOFF
,
AX25_RESPONSE
);
break
;
break
;
}
}
}
}
}
}
ax25_start_heartbeat
(
ax25
);
ax25_start_heartbeat
(
ax25
);
...
@@ -117,53 +103,53 @@ void ax25_std_idletimer_expiry(ax25_cb *ax25)
...
@@ -117,53 +103,53 @@ void ax25_std_idletimer_expiry(ax25_cb *ax25)
void
ax25_std_t1timer_expiry
(
ax25_cb
*
ax25
)
void
ax25_std_t1timer_expiry
(
ax25_cb
*
ax25
)
{
{
switch
(
ax25
->
state
)
{
switch
(
ax25
->
state
)
{
case
AX25_STATE_1
:
case
AX25_STATE_1
:
if
(
ax25
->
n2count
==
ax25
->
n2
)
{
if
(
ax25
->
n2count
==
ax25
->
n2
)
{
if
(
ax25
->
modulus
==
AX25_MODULUS
)
{
if
(
ax25
->
modulus
==
AX25_MODULUS
)
{
ax25_disconnect
(
ax25
,
ETIMEDOUT
);
return
;
}
else
{
ax25
->
modulus
=
AX25_MODULUS
;
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_WINDOW
];
ax25
->
n2count
=
0
;
ax25_send_control
(
ax25
,
AX25_SABM
,
AX25_POLLON
,
AX25_COMMAND
);
}
}
else
{
ax25
->
n2count
++
;
if
(
ax25
->
modulus
==
AX25_MODULUS
)
ax25_send_control
(
ax25
,
AX25_SABM
,
AX25_POLLON
,
AX25_COMMAND
);
else
ax25_send_control
(
ax25
,
AX25_SABME
,
AX25_POLLON
,
AX25_COMMAND
);
}
break
;
case
AX25_STATE_2
:
if
(
ax25
->
n2count
==
ax25
->
n2
)
{
ax25_send_control
(
ax25
,
AX25_DISC
,
AX25_POLLON
,
AX25_COMMAND
);
ax25_disconnect
(
ax25
,
ETIMEDOUT
);
ax25_disconnect
(
ax25
,
ETIMEDOUT
);
return
;
return
;
}
else
{
}
else
{
ax25
->
n2count
++
;
ax25
->
modulus
=
AX25_MODULUS
;
ax25_send_control
(
ax25
,
AX25_DISC
,
AX25_POLLON
,
AX25_COMMAND
);
ax25
->
window
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_WINDOW
];
ax25
->
n2count
=
0
;
ax25_send_control
(
ax25
,
AX25_SABM
,
AX25_POLLON
,
AX25_COMMAND
);
}
}
break
;
}
else
{
ax25
->
n2count
++
;
case
AX25_STATE_3
:
if
(
ax25
->
modulus
==
AX25_MODULUS
)
ax25
->
n2count
=
1
;
ax25_send_control
(
ax25
,
AX25_SABM
,
AX25_POLLON
,
AX25_COMMAND
);
else
ax25_send_control
(
ax25
,
AX25_SABME
,
AX25_POLLON
,
AX25_COMMAND
);
}
break
;
case
AX25_STATE_2
:
if
(
ax25
->
n2count
==
ax25
->
n2
)
{
ax25_send_control
(
ax25
,
AX25_DISC
,
AX25_POLLON
,
AX25_COMMAND
);
ax25_disconnect
(
ax25
,
ETIMEDOUT
);
return
;
}
else
{
ax25
->
n2count
++
;
ax25_send_control
(
ax25
,
AX25_DISC
,
AX25_POLLON
,
AX25_COMMAND
);
}
break
;
case
AX25_STATE_3
:
ax25
->
n2count
=
1
;
ax25_std_transmit_enquiry
(
ax25
);
ax25
->
state
=
AX25_STATE_4
;
break
;
case
AX25_STATE_4
:
if
(
ax25
->
n2count
==
ax25
->
n2
)
{
ax25_send_control
(
ax25
,
AX25_DM
,
AX25_POLLON
,
AX25_RESPONSE
);
ax25_disconnect
(
ax25
,
ETIMEDOUT
);
return
;
}
else
{
ax25
->
n2count
++
;
ax25_std_transmit_enquiry
(
ax25
);
ax25_std_transmit_enquiry
(
ax25
);
ax25
->
state
=
AX25_STATE_4
;
}
break
;
break
;
case
AX25_STATE_4
:
if
(
ax25
->
n2count
==
ax25
->
n2
)
{
ax25_send_control
(
ax25
,
AX25_DM
,
AX25_POLLON
,
AX25_RESPONSE
);
ax25_disconnect
(
ax25
,
ETIMEDOUT
);
return
;
}
else
{
ax25
->
n2count
++
;
ax25_std_transmit_enquiry
(
ax25
);
}
break
;
}
}
ax25_calculate_t1
(
ax25
);
ax25_calculate_t1
(
ax25
);
...
...
net/ax25/ax25_subr.c
View file @
b331768e
/*
/*
* 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)
* This module:
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* This module is free software; you can redistribute it and/or
* Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
* 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.
*/
*/
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
...
@@ -172,9 +148,9 @@ int ax25_decode(ax25_cb *ax25, struct sk_buff *skb, int *ns, int *nr, int *pf)
...
@@ -172,9 +148,9 @@ int ax25_decode(ax25_cb *ax25, struct sk_buff *skb, int *ns, int *nr, int *pf)
return
frametype
;
return
frametype
;
}
}
/*
/*
* This routine is called when the HDLC layer internally generates a
* This routine is called when the HDLC layer internally generates a
* command or response for the remote machine ( eg. RR, UA etc. ).
* command or response for the remote machine ( eg. RR, UA etc. ).
* Only supervisory or unnumbered frames are processed.
* Only supervisory or unnumbered frames are processed.
*/
*/
void
ax25_send_control
(
ax25_cb
*
ax25
,
int
frametype
,
int
poll_bit
,
int
type
)
void
ax25_send_control
(
ax25_cb
*
ax25
,
int
frametype
,
int
poll_bit
,
int
type
)
...
@@ -231,7 +207,7 @@ void ax25_return_dm(struct net_device *dev, ax25_address *src, ax25_address *des
...
@@ -231,7 +207,7 @@ void ax25_return_dm(struct net_device *dev, ax25_address *src, ax25_address *des
skb_reserve
(
skb
,
AX25_BPQ_HEADER_LEN
+
ax25_addr_size
(
digi
));
skb_reserve
(
skb
,
AX25_BPQ_HEADER_LEN
+
ax25_addr_size
(
digi
));
skb
->
nh
.
raw
=
skb
->
data
;
skb
->
nh
.
raw
=
skb
->
data
;
ax25_digi_invert
(
digi
,
&
retdigi
);
ax25_digi_invert
(
digi
,
&
retdigi
);
dptr
=
skb_put
(
skb
,
1
);
dptr
=
skb_put
(
skb
,
1
);
...
@@ -257,18 +233,18 @@ void ax25_calculate_t1(ax25_cb *ax25)
...
@@ -257,18 +233,18 @@ void ax25_calculate_t1(ax25_cb *ax25)
int
n
,
t
=
2
;
int
n
,
t
=
2
;
switch
(
ax25
->
backoff
)
{
switch
(
ax25
->
backoff
)
{
case
0
:
case
0
:
break
;
break
;
case
1
:
case
1
:
t
+=
2
*
ax25
->
n2count
;
t
+=
2
*
ax25
->
n2count
;
break
;
break
;
case
2
:
case
2
:
for
(
n
=
0
;
n
<
ax25
->
n2count
;
n
++
)
for
(
n
=
0
;
n
<
ax25
->
n2count
;
n
++
)
t
*=
2
;
t
*=
2
;
if
(
t
>
8
)
t
=
8
;
if
(
t
>
8
)
t
=
8
;
break
;
break
;
}
}
ax25
->
t1
=
t
*
ax25
->
rtt
;
ax25
->
t1
=
t
*
ax25
->
rtt
;
...
...
net/ax25/ax25_timer.c
View file @
b331768e
/*
/*
* 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)
* This module:
* Copyright (C) Tomi Manninen OH2BNS (oh2bns@sral.fi)
* This module is free software; you can redistribute it and/or
* Copyright (C) Darryl Miles G7LED (dlm@g7led.demon.co.uk)
* modify it under the terms of the GNU General Public License
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* as published by the Free Software Foundation; either version
* Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
* 2 of the License, or (at your option) any later version.
* Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org)
*
* 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).
*/
*/
#include <linux/config.h>
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
...
@@ -152,105 +139,121 @@ unsigned long ax25_display_timer(struct timer_list *timer)
...
@@ -152,105 +139,121 @@ unsigned long ax25_display_timer(struct timer_list *timer)
static
void
ax25_heartbeat_expiry
(
unsigned
long
param
)
static
void
ax25_heartbeat_expiry
(
unsigned
long
param
)
{
{
ax25_cb
*
ax25
=
(
ax25_cb
*
)
param
;
int
proto
=
AX25_PROTO_STD_SIMPLEX
;
int
proto
=
AX25_PROTO_STD_SIMPLEX
;
ax25_cb
*
ax25
=
(
ax25_cb
*
)
param
;
struct
sock
*
sk
=
ax25
->
sk
;
if
(
ax25
->
ax25_dev
)
if
(
ax25
->
ax25_dev
)
proto
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
];
proto
=
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
];
bh_lock_sock
(
sk
);
switch
(
proto
)
{
switch
(
proto
)
{
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
ax25_std_heartbeat_expiry
(
ax25
);
ax25_std_heartbeat_expiry
(
ax25
);
break
;
break
;
#ifdef CONFIG_AX25_DAMA_SLAVE
#ifdef CONFIG_AX25_DAMA_SLAVE
case
AX25_PROTO_DAMA_SLAVE
:
case
AX25_PROTO_DAMA_SLAVE
:
if
(
ax25
->
ax25_dev
->
dama
.
slave
)
if
(
ax25
->
ax25_dev
->
dama
.
slave
)
ax25_ds_heartbeat_expiry
(
ax25
);
ax25_ds_heartbeat_expiry
(
ax25
);
else
else
ax25_std_heartbeat_expiry
(
ax25
);
ax25_std_heartbeat_expiry
(
ax25
);
break
;
break
;
#endif
#endif
}
}
bh_unlock_sock
(
sk
);
}
}
static
void
ax25_t1timer_expiry
(
unsigned
long
param
)
static
void
ax25_t1timer_expiry
(
unsigned
long
param
)
{
{
ax25_cb
*
ax25
=
(
ax25_cb
*
)
param
;
ax25_cb
*
ax25
=
(
ax25_cb
*
)
param
;
struct
sock
*
sk
=
ax25
->
sk
;
bh_lock_sock
(
sk
);
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
ax25_std_t1timer_expiry
(
ax25
);
ax25_std_t1timer_expiry
(
ax25
);
break
;
break
;
#ifdef CONFIG_AX25_DAMA_SLAVE
#ifdef CONFIG_AX25_DAMA_SLAVE
case
AX25_PROTO_DAMA_SLAVE
:
case
AX25_PROTO_DAMA_SLAVE
:
if
(
!
ax25
->
ax25_dev
->
dama
.
slave
)
if
(
!
ax25
->
ax25_dev
->
dama
.
slave
)
ax25_std_t1timer_expiry
(
ax25
);
ax25_std_t1timer_expiry
(
ax25
);
break
;
break
;
#endif
#endif
}
}
bh_unlock_sock
(
sk
);
}
}
static
void
ax25_t2timer_expiry
(
unsigned
long
param
)
static
void
ax25_t2timer_expiry
(
unsigned
long
param
)
{
{
ax25_cb
*
ax25
=
(
ax25_cb
*
)
param
;
ax25_cb
*
ax25
=
(
ax25_cb
*
)
param
;
struct
sock
*
sk
=
ax25
->
sk
;
bh_lock_sock
(
sk
);
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
ax25_std_t2timer_expiry
(
ax25
);
ax25_std_t2timer_expiry
(
ax25
);
break
;
break
;
#ifdef CONFIG_AX25_DAMA_SLAVE
#ifdef CONFIG_AX25_DAMA_SLAVE
case
AX25_PROTO_DAMA_SLAVE
:
case
AX25_PROTO_DAMA_SLAVE
:
if
(
!
ax25
->
ax25_dev
->
dama
.
slave
)
if
(
!
ax25
->
ax25_dev
->
dama
.
slave
)
ax25_std_t2timer_expiry
(
ax25
);
ax25_std_t2timer_expiry
(
ax25
);
break
;
break
;
#endif
#endif
}
}
bh_unlock_sock
(
sk
);
}
}
static
void
ax25_t3timer_expiry
(
unsigned
long
param
)
static
void
ax25_t3timer_expiry
(
unsigned
long
param
)
{
{
ax25_cb
*
ax25
=
(
ax25_cb
*
)
param
;
ax25_cb
*
ax25
=
(
ax25_cb
*
)
param
;
struct
sock
*
sk
=
ax25
->
sk
;
bh_lock_sock
(
sk
);
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
ax25_std_t3timer_expiry
(
ax25
);
ax25_std_t3timer_expiry
(
ax25
);
break
;
break
;
#ifdef CONFIG_AX25_DAMA_SLAVE
#ifdef CONFIG_AX25_DAMA_SLAVE
case
AX25_PROTO_DAMA_SLAVE
:
case
AX25_PROTO_DAMA_SLAVE
:
if
(
ax25
->
ax25_dev
->
dama
.
slave
)
if
(
ax25
->
ax25_dev
->
dama
.
slave
)
ax25_ds_t3timer_expiry
(
ax25
);
ax25_ds_t3timer_expiry
(
ax25
);
else
else
ax25_std_t3timer_expiry
(
ax25
);
ax25_std_t3timer_expiry
(
ax25
);
break
;
break
;
#endif
#endif
}
}
bh_unlock_sock
(
sk
);
}
}
static
void
ax25_idletimer_expiry
(
unsigned
long
param
)
static
void
ax25_idletimer_expiry
(
unsigned
long
param
)
{
{
ax25_cb
*
ax25
=
(
ax25_cb
*
)
param
;
ax25_cb
*
ax25
=
(
ax25_cb
*
)
param
;
struct
sock
*
sk
=
ax25
->
sk
;
bh_lock_sock
(
sk
);
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
switch
(
ax25
->
ax25_dev
->
values
[
AX25_VALUES_PROTOCOL
])
{
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_SIMPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
case
AX25_PROTO_STD_DUPLEX
:
ax25_std_idletimer_expiry
(
ax25
);
ax25_std_idletimer_expiry
(
ax25
);
break
;
break
;
#ifdef CONFIG_AX25_DAMA_SLAVE
#ifdef CONFIG_AX25_DAMA_SLAVE
case
AX25_PROTO_DAMA_SLAVE
:
case
AX25_PROTO_DAMA_SLAVE
:
if
(
ax25
->
ax25_dev
->
dama
.
slave
)
if
(
ax25
->
ax25_dev
->
dama
.
slave
)
ax25_ds_idletimer_expiry
(
ax25
);
ax25_ds_idletimer_expiry
(
ax25
);
else
else
ax25_std_idletimer_expiry
(
ax25
);
ax25_std_idletimer_expiry
(
ax25
);
break
;
break
;
#endif
#endif
}
}
bh_unlock_sock
(
sk
);
}
}
net/ax25/ax25_uid.c
View file @
b331768e
/*
/*
* 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) 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.
*
* History
* AX.25 036 Jonathan(G4KLX) Split from af_ax25.c.
*/
*/
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
...
@@ -23,6 +16,7 @@
...
@@ -23,6 +16,7 @@
#include <linux/string.h>
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/net.h>
#include <linux/spinlock.h>
#include <net/ax25.h>
#include <net/ax25.h>
#include <linux/inet.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/netdevice.h>
...
@@ -47,17 +41,23 @@
...
@@ -47,17 +41,23 @@
*/
*/
static
ax25_uid_assoc
*
ax25_uid_list
;
static
ax25_uid_assoc
*
ax25_uid_list
;
static
rwlock_t
ax25_uid_lock
=
RW_LOCK_UNLOCKED
;
int
ax25_uid_policy
=
0
;
int
ax25_uid_policy
=
0
;
ax25_address
*
ax25_findbyuid
(
uid_t
uid
)
ax25_address
*
ax25_findbyuid
(
uid_t
uid
)
{
{
ax25_uid_assoc
*
ax25_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
)
{
for
(
ax25_uid
=
ax25_uid_list
;
ax25_uid
!=
NULL
;
ax25_uid
=
ax25_uid
->
next
)
{
if
(
ax25_uid
->
uid
==
uid
)
if
(
ax25_uid
->
uid
==
uid
)
{
return
&
ax25_uid
->
call
;
res
=
&
ax25_uid
->
call
;
break
;
}
}
}
read_unlock
(
&
ax25_uid_lock
);
return
NULL
;
return
NULL
;
}
}
...
@@ -65,63 +65,77 @@ ax25_address *ax25_findbyuid(uid_t uid)
...
@@ -65,63 +65,77 @@ ax25_address *ax25_findbyuid(uid_t uid)
int
ax25_uid_ioctl
(
int
cmd
,
struct
sockaddr_ax25
*
sax
)
int
ax25_uid_ioctl
(
int
cmd
,
struct
sockaddr_ax25
*
sax
)
{
{
ax25_uid_assoc
*
s
,
*
ax25_uid
;
ax25_uid_assoc
*
s
,
*
ax25_uid
;
unsigned
long
flag
s
;
unsigned
long
re
s
;
switch
(
cmd
)
{
switch
(
cmd
)
{
case
SIOCAX25GETUID
:
case
SIOCAX25GETUID
:
for
(
ax25_uid
=
ax25_uid_list
;
ax25_uid
!=
NULL
;
ax25_uid
=
ax25_uid
->
next
)
{
res
=
-
ENOENT
;
if
(
ax25cmp
(
&
sax
->
sax25_call
,
&
ax25_uid
->
call
)
==
0
)
read_lock
(
&
ax25_uid_lock
);
return
ax25_uid
->
uid
;
for
(
ax25_uid
=
ax25_uid_list
;
ax25_uid
!=
NULL
;
ax25_uid
=
ax25_uid
->
next
)
{
if
(
ax25cmp
(
&
sax
->
sax25_call
,
&
ax25_uid
->
call
)
==
0
)
{
res
=
ax25_uid
->
uid
;
break
;
}
}
return
-
ENOENT
;
}
read_unlock
(
&
ax25_uid_lock
);
case
SIOCAX25ADDUID
:
return
res
;
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
case
SIOCAX25ADDUID
:
if
(
ax25_findbyuid
(
sax
->
sax25_uid
))
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EEXIST
;
return
-
EPERM
;
if
(
sax
->
sax25_uid
==
0
)
if
(
ax25_findbyuid
(
sax
->
sax25_uid
))
return
-
EINVAL
;
return
-
EEXIST
;
if
((
ax25_uid
=
kmalloc
(
sizeof
(
*
ax25_uid
),
GFP_KERNEL
))
==
NULL
)
if
(
sax
->
sax25_uid
==
0
)
return
-
ENOMEM
;
return
-
EINVAL
;
ax25_uid
->
uid
=
sax
->
sax25_uid
;
if
((
ax25_uid
=
kmalloc
(
sizeof
(
*
ax25_uid
),
GFP_KERNEL
))
==
NULL
)
ax25_uid
->
call
=
sax
->
sax25_call
;
return
-
ENOMEM
;
save_flags
(
flags
);
cli
();
ax25_uid
->
next
=
ax25_uid_list
;
ax25_uid
->
uid
=
sax
->
sax25_uid
;
ax25_uid_list
=
ax25_uid
;
ax25_uid
->
call
=
sax
->
sax25_call
;
restore_flags
(
flags
);
return
0
;
write_lock
(
&
ax25_uid_lock
);
ax25_uid
->
next
=
ax25_uid_list
;
ax25_uid_list
=
ax25_uid
;
write_unlock
(
&
ax25_uid_lock
);
return
0
;
case
SIOCAX25DELUID
:
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
case
SIOCAX25DELUID
:
write_lock
(
&
ax25_uid_lock
);
if
(
!
capable
(
CAP_NET_ADMIN
))
for
(
ax25_uid
=
ax25_uid_list
;
ax25_uid
!=
NULL
;
ax25_uid
=
ax25_uid
->
next
)
{
return
-
EPERM
;
if
(
ax25cmp
(
&
sax
->
sax25_call
,
&
ax25_uid
->
call
)
==
0
)
{
for
(
ax25_uid
=
ax25_uid_list
;
ax25_uid
!=
NULL
;
ax25_uid
=
ax25_uid
->
next
)
{
break
;
if
(
ax25cmp
(
&
sax
->
sax25_call
,
&
ax25_uid
->
call
)
==
0
)
break
;
}
}
if
(
ax25_uid
==
NULL
)
}
return
-
ENOENT
;
if
(
ax25_uid
==
NULL
)
{
save_flags
(
flags
);
cli
();
write_unlock
(
&
ax25_uid_lock
);
if
((
s
=
ax25_uid_list
)
==
ax25_uid
)
{
return
-
ENOENT
;
ax25_uid_list
=
s
->
next
;
}
restore_flags
(
flags
);
if
((
s
=
ax25_uid_list
)
==
ax25_uid
)
{
ax25_uid_list
=
s
->
next
;
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
;
write_unlock
(
&
ax25_uid_lock
);
kfree
(
ax25_uid
);
kfree
(
ax25_uid
);
return
0
;
return
0
;
}
}
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
s
=
s
->
next
;
if
(
s
->
next
==
ax25_uid
)
{
}
s
->
next
=
ax25_uid
->
next
;
write_unlock
(
&
ax25_uid_lock
);
restore_flags
(
flags
);
kfree
(
ax25_uid
);
return
0
;
}
s
=
s
->
next
;
}
restore_flags
(
flags
);
return
-
ENOENT
;
default:
return
-
ENOENT
;
return
-
EINVAL
;
default:
return
-
EINVAL
;
}
}
return
-
EINVAL
;
/*NOTREACHED */
return
-
EINVAL
;
/*NOTREACHED */
...
@@ -134,8 +148,7 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -134,8 +148,7 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length)
off_t
pos
=
0
;
off_t
pos
=
0
;
off_t
begin
=
0
;
off_t
begin
=
0
;
cli
();
read_lock
(
&
ax25_uid_lock
);
len
+=
sprintf
(
buffer
,
"Policy: %d
\n
"
,
ax25_uid_policy
);
len
+=
sprintf
(
buffer
,
"Policy: %d
\n
"
,
ax25_uid_policy
);
for
(
pt
=
ax25_uid_list
;
pt
!=
NULL
;
pt
=
pt
->
next
)
{
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)
...
@@ -151,13 +164,13 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length)
if
(
pos
>
offset
+
length
)
if
(
pos
>
offset
+
length
)
break
;
break
;
}
}
read_unlock
(
&
ax25_uid_lock
);
sti
();
*
start
=
buffer
+
(
offset
-
begin
);
*
start
=
buffer
+
(
offset
-
begin
);
len
-=
offset
-
begin
;
len
-=
offset
-
begin
;
if
(
len
>
length
)
len
=
length
;
if
(
len
>
length
)
len
=
length
;
return
len
;
return
len
;
}
}
...
@@ -167,12 +180,16 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -167,12 +180,16 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length)
*/
*/
void
__exit
ax25_uid_free
(
void
)
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
)
{
while
(
ax25_uid
!=
NULL
)
{
s
=
ax25_uid
;
s
=
ax25_uid
;
ax25_uid
=
ax25_uid
->
next
;
ax25_uid
=
ax25_uid
->
next
;
kfree
(
s
);
kfree
(
s
);
}
}
ax25_uid_list
=
NULL
;
write_unlock
(
&
ax25_uid_lock
);
}
}
net/ax25/sysctl_net_ax25.c
View file @
b331768e
/* -*- 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.
* Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com)
* Added /proc/sys/net/ax25 directory entry (empty =) ). [MS]
*/
*/
#include <linux/config.h>
#include <linux/config.h>
#include <linux/mm.h>
#include <linux/mm.h>
#include <linux/sysctl.h>
#include <linux/sysctl.h>
#include <linux/spinlock.h>
#include <net/ax25.h>
#include <net/ax25.h>
static
int
min_ipdefmode
[]
=
{
0
},
max_ipdefmode
[]
=
{
1
};
static
int
min_ipdefmode
[]
=
{
0
},
max_ipdefmode
[]
=
{
1
};
...
@@ -105,6 +107,7 @@ void ax25_register_sysctl(void)
...
@@ -105,6 +107,7 @@ void ax25_register_sysctl(void)
ax25_dev
*
ax25_dev
;
ax25_dev
*
ax25_dev
;
int
n
,
k
;
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
)
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
);
ax25_table_size
+=
sizeof
(
ctl_table
);
...
@@ -119,6 +122,7 @@ void ax25_register_sysctl(void)
...
@@ -119,6 +122,7 @@ void ax25_register_sysctl(void)
while
(
n
--
)
while
(
n
--
)
kfree
(
ax25_table
[
n
].
child
);
kfree
(
ax25_table
[
n
].
child
);
kfree
(
ax25_table
);
kfree
(
ax25_table
);
spin_unlock_bh
(
&
ax25_dev_lock
);
return
;
return
;
}
}
memcpy
(
child
,
ax25_param_table
,
sizeof
(
ax25_param_table
));
memcpy
(
child
,
ax25_param_table
,
sizeof
(
ax25_param_table
));
...
@@ -128,7 +132,7 @@ void ax25_register_sysctl(void)
...
@@ -128,7 +132,7 @@ void ax25_register_sysctl(void)
ax25_table
[
n
].
mode
=
0555
;
ax25_table
[
n
].
mode
=
0555
;
#ifndef CONFIG_AX25_DAMA_SLAVE
#ifndef CONFIG_AX25_DAMA_SLAVE
/*
/*
* We do not wish to have a representation of this parameter
* We do not wish to have a representation of this parameter
* in /proc/sys/ when configured *not* to include the
* in /proc/sys/ when configured *not* to include the
* AX.25 DAMA slave code, do we?
* AX.25 DAMA slave code, do we?
...
@@ -144,6 +148,7 @@ void ax25_register_sysctl(void)
...
@@ -144,6 +148,7 @@ void ax25_register_sysctl(void)
n
++
;
n
++
;
}
}
spin_unlock_bh
(
&
ax25_dev_lock
);
ax25_dir_table
[
0
].
child
=
ax25_table
;
ax25_dir_table
[
0
].
child
=
ax25_table
;
...
...
net/netrom/af_netrom.c
View file @
b331768e
/*
/*
* 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
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*
* Copyright Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* This module:
* Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk)
* 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
*/
*/
#include <linux/config.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/errno.h>
...
@@ -82,7 +57,8 @@ int sysctl_netrom_link_fails_count = NR_DEFAULT_FAILS;
...
@@ -82,7 +57,8 @@ int sysctl_netrom_link_fails_count = NR_DEFAULT_FAILS;
static
unsigned
short
circuit
=
0x101
;
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
;
static
struct
proto_ops
nr_proto_ops
;
...
@@ -123,27 +99,26 @@ decmod: MOD_DEC_USE_COUNT;
...
@@ -123,27 +99,26 @@ decmod: MOD_DEC_USE_COUNT;
static
void
nr_remove_socket
(
struct
sock
*
sk
)
static
void
nr_remove_socket
(
struct
sock
*
sk
)
{
{
struct
sock
*
s
;
struct
sock
*
s
;
unsigned
long
flags
;
s
ave_flags
(
flags
);
cli
(
);
s
pin_lock_bh
(
&
nr_list_lock
);
if
((
s
=
nr_list
)
==
sk
)
{
if
((
s
=
nr_list
)
==
sk
)
{
nr_list
=
s
->
next
;
nr_list
=
s
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_list_lock
);
return
;
return
;
}
}
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
if
(
s
->
next
==
sk
)
{
if
(
s
->
next
==
sk
)
{
s
->
next
=
sk
->
next
;
s
->
next
=
sk
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_list_lock
);
return
;
return
;
}
}
s
=
s
->
next
;
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)
...
@@ -153,10 +128,12 @@ static void nr_kill_by_device(struct net_device *dev)
{
{
struct
sock
*
s
;
struct
sock
*
s
;
spin_lock_bh
(
&
nr_list_lock
);
for
(
s
=
nr_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
for
(
s
=
nr_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
if
(
nr_sk
(
s
)
->
device
==
dev
)
if
(
nr_sk
(
s
)
->
device
==
dev
)
nr_disconnect
(
s
,
ENETUNREACH
);
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
...
@@ -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
)
static
void
nr_insert_socket
(
struct
sock
*
sk
)
{
{
unsigned
long
flags
;
spin_lock_bh
(
&
nr_list_lock
);
save_flags
(
flags
);
cli
();
sk
->
next
=
nr_list
;
sk
->
next
=
nr_list
;
nr_list
=
sk
;
nr_list
=
sk
;
spin_unlock_bh
(
&
nr_list_lock
);
restore_flags
(
flags
);
}
}
/*
/*
...
@@ -196,21 +169,18 @@ static void nr_insert_socket(struct sock *sk)
...
@@ -196,21 +169,18 @@ static void nr_insert_socket(struct sock *sk)
*/
*/
static
struct
sock
*
nr_find_listener
(
ax25_address
*
addr
)
static
struct
sock
*
nr_find_listener
(
ax25_address
*
addr
)
{
{
unsigned
long
flags
;
struct
sock
*
s
;
struct
sock
*
s
;
save_flags
(
flags
);
spin_lock_bh
(
&
nr_list_lock
);
cli
();
for
(
s
=
nr_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
for
(
s
=
nr_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
if
(
!
ax25cmp
(
&
nr_sk
(
s
)
->
source_addr
,
addr
)
&&
if
(
!
ax25cmp
(
&
nr_sk
(
s
)
->
source_addr
,
addr
)
&&
s
->
state
==
TCP_LISTEN
)
{
s
->
state
==
TCP_LISTEN
)
{
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_list_lock
);
return
s
;
return
s
;
}
}
}
}
spin_unlock_bh
(
&
nr_list_lock
);
restore_flags
(
flags
);
return
NULL
;
return
NULL
;
}
}
...
@@ -220,21 +190,17 @@ static struct sock *nr_find_listener(ax25_address *addr)
...
@@ -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
)
static
struct
sock
*
nr_find_socket
(
unsigned
char
index
,
unsigned
char
id
)
{
{
struct
sock
*
s
;
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
)
{
for
(
s
=
nr_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
nr_cb
*
nr
=
nr_sk
(
s
);
nr_cb
*
nr
=
nr_sk
(
s
);
if
(
nr
->
my_index
==
index
&&
nr
->
my_id
==
id
)
{
if
(
nr
->
my_index
==
index
&&
nr
->
my_id
==
id
)
{
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_list_lock
);
return
s
;
return
s
;
}
}
}
}
spin_unlock_bh
(
&
nr_list_lock
);
restore_flags
(
flags
);
return
NULL
;
return
NULL
;
}
}
...
@@ -242,25 +208,22 @@ static struct sock *nr_find_socket(unsigned char index, unsigned char id)
...
@@ -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.
* 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
;
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
)
{
for
(
s
=
nr_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
nr_cb
*
nr
=
nr_sk
(
s
);
nr_cb
*
nr
=
nr_sk
(
s
);
if
(
nr
->
your_index
==
index
&&
nr
->
your_id
==
id
&&
if
(
nr
->
your_index
==
index
&&
nr
->
your_id
==
id
&&
!
ax25cmp
(
&
nr
->
dest_addr
,
dest
))
{
!
ax25cmp
(
&
nr
->
dest_addr
,
dest
))
{
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_list_lock
);
return
s
;
return
s
;
}
}
}
}
spin_unlock_bh
(
&
nr_list_lock
);
restore_flags
(
flags
);
return
NULL
;
return
NULL
;
}
}
...
@@ -301,17 +264,16 @@ static void nr_destroy_timer(unsigned long data)
...
@@ -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
* This is called from user mode and the timers. Thus it protects itself
*
interrupt users but doesn't worry about being called during work.
*
against interrupt users but doesn't worry about being called during
*
Once it is removed from the queue no interrupt or bottom half will
*
work. Once it is removed from the queue no interrupt or bottom half
* touch it and we are (fairly 8-) ) safe.
*
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
;
struct
sk_buff
*
skb
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
(
);
nr_remove_socket
(
sk
);
nr_stop_heartbeat
(
sk
);
nr_stop_heartbeat
(
sk
);
nr_stop_t1timer
(
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
...
@@ -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_t4timer
(
sk
);
nr_stop_idletimer
(
sk
);
nr_stop_idletimer
(
sk
);
nr_remove_socket
(
sk
);
nr_clear_queues
(
sk
);
/* Flush the queues */
nr_clear_queues
(
sk
);
/* Flush the queues */
while
((
skb
=
skb_dequeue
(
&
sk
->
receive_queue
))
!=
NULL
)
{
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
...
@@ -342,8 +303,6 @@ void nr_destroy_socket(struct sock *sk) /* Not static as it's used by the timer
}
else
{
}
else
{
nr_free_sock
(
sk
);
nr_free_sock
(
sk
);
}
}
restore_flags
(
flags
);
}
}
/*
/*
...
@@ -368,38 +327,38 @@ static int nr_setsockopt(struct socket *sock, int level, int optname,
...
@@ -368,38 +327,38 @@ static int nr_setsockopt(struct socket *sock, int level, int optname,
return
-
EFAULT
;
return
-
EFAULT
;
switch
(
optname
)
{
switch
(
optname
)
{
case
NETROM_T1
:
case
NETROM_T1
:
if
(
opt
<
1
)
if
(
opt
<
1
)
return
-
EINVAL
;
return
-
EINVAL
;
nr
->
t1
=
opt
*
HZ
;
nr
->
t1
=
opt
*
HZ
;
return
0
;
return
0
;
case
NETROM_T2
:
case
NETROM_T2
:
if
(
opt
<
1
)
if
(
opt
<
1
)
return
-
EINVAL
;
return
-
EINVAL
;
nr
->
t2
=
opt
*
HZ
;
nr
->
t2
=
opt
*
HZ
;
return
0
;
return
0
;
case
NETROM_N2
:
case
NETROM_N2
:
if
(
opt
<
1
||
opt
>
31
)
if
(
opt
<
1
||
opt
>
31
)
return
-
EINVAL
;
return
-
EINVAL
;
nr
->
n2
=
opt
;
nr
->
n2
=
opt
;
return
0
;
return
0
;
case
NETROM_T4
:
case
NETROM_T4
:
if
(
opt
<
1
)
if
(
opt
<
1
)
return
-
EINVAL
;
return
-
EINVAL
;
nr
->
t4
=
opt
*
HZ
;
nr
->
t4
=
opt
*
HZ
;
return
0
;
return
0
;
case
NETROM_IDLE
:
case
NETROM_IDLE
:
if
(
opt
<
0
)
if
(
opt
<
0
)
return
-
EINVAL
;
return
-
EINVAL
;
nr
->
idle
=
opt
*
60
*
HZ
;
nr
->
idle
=
opt
*
60
*
HZ
;
return
0
;
return
0
;
default:
default:
return
-
ENOPROTOOPT
;
return
-
ENOPROTOOPT
;
}
}
}
}
...
@@ -421,28 +380,28 @@ static int nr_getsockopt(struct socket *sock, int level, int optname,
...
@@ -421,28 +380,28 @@ static int nr_getsockopt(struct socket *sock, int level, int optname,
return
-
EINVAL
;
return
-
EINVAL
;
switch
(
optname
)
{
switch
(
optname
)
{
case
NETROM_T1
:
case
NETROM_T1
:
val
=
nr
->
t1
/
HZ
;
val
=
nr
->
t1
/
HZ
;
break
;
break
;
case
NETROM_T2
:
case
NETROM_T2
:
val
=
nr
->
t2
/
HZ
;
val
=
nr
->
t2
/
HZ
;
break
;
break
;
case
NETROM_N2
:
case
NETROM_N2
:
val
=
nr
->
n2
;
val
=
nr
->
n2
;
break
;
break
;
case
NETROM_T4
:
case
NETROM_T4
:
val
=
nr
->
t4
/
HZ
;
val
=
nr
->
t4
/
HZ
;
break
;
break
;
case
NETROM_IDLE
:
case
NETROM_IDLE
:
val
=
nr
->
idle
/
(
60
*
HZ
);
val
=
nr
->
idle
/
(
60
*
HZ
);
break
;
break
;
default:
default:
return
-
ENOPROTOOPT
;
return
-
ENOPROTOOPT
;
}
}
len
=
min_t
(
unsigned
int
,
len
,
sizeof
(
int
));
len
=
min_t
(
unsigned
int
,
len
,
sizeof
(
int
));
...
@@ -567,34 +526,33 @@ static int nr_release(struct socket *sock)
...
@@ -567,34 +526,33 @@ static int nr_release(struct socket *sock)
nr
=
nr_sk
(
sk
);
nr
=
nr_sk
(
sk
);
switch
(
nr
->
state
)
{
switch
(
nr
->
state
)
{
case
NR_STATE_0
:
case
NR_STATE_0
:
case
NR_STATE_1
:
case
NR_STATE_1
:
case
NR_STATE_2
:
case
NR_STATE_2
:
nr_disconnect
(
sk
,
0
);
nr_disconnect
(
sk
,
0
);
nr_destroy_socket
(
sk
);
nr_destroy_socket
(
sk
);
break
;
break
;
case
NR_STATE_3
:
case
NR_STATE_3
:
nr_clear_queues
(
sk
);
nr_clear_queues
(
sk
);
nr
->
n2count
=
0
;
nr
->
n2count
=
0
;
nr_write_internal
(
sk
,
NR_DISCREQ
);
nr_write_internal
(
sk
,
NR_DISCREQ
);
nr_start_t1timer
(
sk
);
nr_start_t1timer
(
sk
);
nr_stop_t2timer
(
sk
);
nr_stop_t2timer
(
sk
);
nr_stop_t4timer
(
sk
);
nr_stop_t4timer
(
sk
);
nr_stop_idletimer
(
sk
);
nr_stop_idletimer
(
sk
);
nr
->
state
=
NR_STATE_2
;
nr
->
state
=
NR_STATE_2
;
sk
->
state
=
TCP_CLOSE
;
sk
->
state
=
TCP_CLOSE
;
sk
->
shutdown
|=
SEND_SHUTDOWN
;
sk
->
shutdown
|=
SEND_SHUTDOWN
;
sk
->
state_change
(
sk
);
sk
->
state_change
(
sk
);
sk
->
dead
=
1
;
sk
->
dead
=
1
;
sk
->
destroy
=
1
;
sk
->
destroy
=
1
;
sk
->
socket
=
NULL
;
sk
->
socket
=
NULL
;
break
;
break
;
default:
default:
sk
->
socket
=
NULL
;
sk
->
socket
=
NULL
;
break
;
break
;
}
}
sock
->
sk
=
NULL
;
sock
->
sk
=
NULL
;
...
@@ -732,78 +690,98 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
...
@@ -732,78 +690,98 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
if
(
sk
->
state
!=
TCP_ESTABLISHED
&&
(
flags
&
O_NONBLOCK
))
if
(
sk
->
state
!=
TCP_ESTABLISHED
&&
(
flags
&
O_NONBLOCK
))
return
-
EINPROGRESS
;
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
)
{
if
(
sk
->
state
==
TCP_SYN_SENT
)
{
interruptible_sleep_on
(
sk
->
sleep
);
struct
task_struct
*
tsk
=
current
;
if
(
signal_pending
(
current
))
{
DECLARE_WAITQUEUE
(
wait
,
tsk
);
sti
();
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
;
return
-
ERESTARTSYS
;
}
}
current
->
state
=
TASK_RUNNING
;
remove_wait_queue
(
sk
->
sleep
,
&
wait
);
}
}
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
{
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
{
sti
();
sock
->
state
=
SS_UNCONNECTED
;
sock
->
state
=
SS_UNCONNECTED
;
return
sock_error
(
sk
);
/* Always set at this point */
return
sock_error
(
sk
);
/* Always set at this point */
}
}
sock
->
state
=
SS_CONNECTED
;
sock
->
state
=
SS_CONNECTED
;
sti
();
return
0
;
return
0
;
}
}
static
int
nr_accept
(
struct
socket
*
sock
,
struct
socket
*
newsock
,
int
flags
)
static
int
nr_accept
(
struct
socket
*
sock
,
struct
socket
*
newsock
,
int
flags
)
{
{
struct
sock
*
sk
;
struct
task_struct
*
tsk
=
current
;
struct
sock
*
newsk
;
DECLARE_WAITQUEUE
(
wait
,
tsk
)
;
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
struct
sock
*
newsk
;
struct
sock
*
sk
;
int
err
=
0
;
if
((
sk
=
sock
->
sk
)
==
NULL
)
if
((
sk
=
sock
->
sk
)
==
NULL
)
return
-
EINVAL
;
return
-
EINVAL
;
if
(
sk
->
type
!=
SOCK_SEQPACKET
)
lock_sock
(
sk
);
return
-
EOPNOTSUPP
;
if
(
sk
->
type
!=
SOCK_SEQPACKET
)
{
err
=
-
EOPNOTSUPP
;
goto
out
;
}
if
(
sk
->
state
!=
TCP_LISTEN
)
if
(
sk
->
state
!=
TCP_LISTEN
)
{
return
-
EINVAL
;
err
=
-
EINVAL
;
goto
out
;
}
/*
/*
* The write queue this time is holding sockets ready to use
* The write queue this time is holding sockets ready to use
* hooked into the SABM we saved
* hooked into the SABM we saved
*/
*/
do
{
add_wait_queue
(
sk
->
sleep
,
&
wait
);
cli
();
for
(;;)
{
if
((
skb
=
skb_dequeue
(
&
sk
->
receive_queue
))
==
NULL
)
{
skb
=
skb_dequeue
(
&
sk
->
receive_queue
);
if
(
flags
&
O_NONBLOCK
)
{
if
(
skb
)
sti
();
break
;
return
-
EWOULDBLOCK
;
}
current
->
state
=
TASK_INTERRUPTIBLE
;
interruptible_sleep_on
(
sk
->
sleep
);
release_sock
(
sk
);
if
(
signal_pending
(
current
))
{
if
(
flags
&
O_NONBLOCK
)
sti
();
return
-
EWOULDBLOCK
;
return
-
ERESTARTSYS
;
if
(
!
signal_pending
(
tsk
))
{
}
schedule
();
lock_sock
(
sk
);
continue
;
}
}
}
while
(
skb
==
NULL
);
return
-
ERESTARTSYS
;
}
current
->
state
=
TASK_RUNNING
;
remove_wait_queue
(
sk
->
sleep
,
&
wait
);
newsk
=
skb
->
sk
;
newsk
=
skb
->
sk
;
newsk
->
pair
=
NULL
;
newsk
->
pair
=
NULL
;
newsk
->
socket
=
newsock
;
newsk
->
socket
=
newsock
;
newsk
->
sleep
=
&
newsock
->
wait
;
newsk
->
sleep
=
&
newsock
->
wait
;
sti
();
/* Now attach up the new socket */
/* Now attach up the new socket */
kfree_skb
(
skb
);
kfree_skb
(
skb
);
sk
->
ack_backlog
--
;
sk
->
ack_backlog
--
;
newsock
->
sk
=
newsk
;
newsock
->
sk
=
newsk
;
return
0
;
out:
return
err
;
}
}
static
int
nr_getname
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
static
int
nr_getname
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
...
@@ -1127,54 +1105,53 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
...
@@ -1127,54 +1105,53 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
struct
sock
*
sk
=
sock
->
sk
;
struct
sock
*
sk
=
sock
->
sk
;
switch
(
cmd
)
{
switch
(
cmd
)
{
case
TIOCOUTQ
:
{
case
TIOCOUTQ
:
{
long
amount
;
long
amount
;
amount
=
sk
->
sndbuf
-
atomic_read
(
&
sk
->
wmem_alloc
);
amount
=
sk
->
sndbuf
-
atomic_read
(
&
sk
->
wmem_alloc
);
if
(
amount
<
0
)
if
(
amount
<
0
)
amount
=
0
;
amount
=
0
;
return
put_user
(
amount
,
(
int
*
)
arg
);
return
put_user
(
amount
,
(
int
*
)
arg
);
}
}
case
TIOCINQ
:
{
case
TIOCINQ
:
{
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
long
amount
=
0L
;
long
amount
=
0L
;
/* These two are safe on a single CPU system as only user tasks fiddle here */
/* These two are safe on a single CPU system as only user tasks fiddle here */
if
((
skb
=
skb_peek
(
&
sk
->
receive_queue
))
!=
NULL
)
if
((
skb
=
skb_peek
(
&
sk
->
receive_queue
))
!=
NULL
)
amount
=
skb
->
len
;
amount
=
skb
->
len
;
return
put_user
(
amount
,
(
int
*
)
arg
);
return
put_user
(
amount
,
(
int
*
)
arg
);
}
}
case
SIOCGSTAMP
:
case
SIOCGSTAMP
:
if
(
sk
!=
NULL
)
{
if
(
sk
!=
NULL
)
{
if
(
sk
->
stamp
.
tv_sec
==
0
)
if
(
sk
->
stamp
.
tv_sec
==
0
)
return
-
ENOENT
;
return
-
ENOENT
;
return
copy_to_user
((
void
*
)
arg
,
&
sk
->
stamp
,
sizeof
(
struct
timeval
))
?
-
EFAULT
:
0
;
return
copy_to_user
((
void
*
)
arg
,
&
sk
->
stamp
,
sizeof
(
struct
timeval
))
?
-
EFAULT
:
0
;
}
}
return
-
EINVAL
;
return
-
EINVAL
;
case
SIOCGIFADDR
:
case
SIOCGIFADDR
:
case
SIOCSIFADDR
:
case
SIOCSIFADDR
:
case
SIOCGIFDSTADDR
:
case
SIOCGIFDSTADDR
:
case
SIOCSIFDSTADDR
:
case
SIOCSIFDSTADDR
:
case
SIOCGIFBRDADDR
:
case
SIOCGIFBRDADDR
:
case
SIOCSIFBRDADDR
:
case
SIOCSIFBRDADDR
:
case
SIOCGIFNETMASK
:
case
SIOCGIFNETMASK
:
case
SIOCSIFNETMASK
:
case
SIOCSIFNETMASK
:
case
SIOCGIFMETRIC
:
case
SIOCGIFMETRIC
:
case
SIOCSIFMETRIC
:
case
SIOCSIFMETRIC
:
return
-
EINVAL
;
return
-
EINVAL
;
case
SIOCADDRT
:
case
SIOCADDRT
:
case
SIOCDELRT
:
case
SIOCDELRT
:
case
SIOCNRDECOBS
:
case
SIOCNRDECOBS
:
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
return
nr_rt_ioctl
(
cmd
,
(
void
*
)
arg
);
return
nr_rt_ioctl
(
cmd
,
(
void
*
)
arg
);
default:
default:
return
dev_ioctl
(
cmd
,
(
void
*
)
arg
);
return
dev_ioctl
(
cmd
,
(
void
*
)
arg
);
}
}
/*NOTREACHED*/
return
0
;
return
0
;
}
}
...
@@ -1187,7 +1164,7 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -1187,7 +1164,7 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length)
off_t
pos
=
0
;
off_t
pos
=
0
;
off_t
begin
=
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
"
);
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,47 +1217,45 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -1240,47 +1217,45 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length)
break
;
break
;
}
}
s
ti
(
);
s
pin_unlock_bh
(
&
nr_list_lock
);
*
start
=
buffer
+
(
offset
-
begin
);
*
start
=
buffer
+
(
offset
-
begin
);
len
-=
(
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
=
{
static
struct
net_proto_family
nr_family_ops
=
{
.
family
=
PF_NETROM
,
.
family
=
PF_NETROM
,
.
create
=
nr_create
,
.
create
=
nr_create
,
};
};
static
struct
proto_ops
SOCKOPS_WRAPPED
(
nr_proto_ops
)
=
{
static
struct
proto_ops
nr_proto_ops
=
{
.
family
=
PF_NETROM
,
.
family
=
PF_NETROM
,
.
release
=
nr_release
,
.
release
=
nr_release
,
.
bind
=
nr_bind
,
.
bind
=
nr_bind
,
.
connect
=
nr_connect
,
.
connect
=
nr_connect
,
.
socketpair
=
sock_no_socketpair
,
.
socketpair
=
sock_no_socketpair
,
.
accept
=
nr_accept
,
.
accept
=
nr_accept
,
.
getname
=
nr_getname
,
.
getname
=
nr_getname
,
.
poll
=
datagram_poll
,
.
poll
=
datagram_poll
,
.
ioctl
=
nr_ioctl
,
.
ioctl
=
nr_ioctl
,
.
listen
=
nr_listen
,
.
listen
=
nr_listen
,
.
shutdown
=
sock_no_shutdown
,
.
shutdown
=
sock_no_shutdown
,
.
setsockopt
=
nr_setsockopt
,
.
setsockopt
=
nr_setsockopt
,
.
getsockopt
=
nr_getsockopt
,
.
getsockopt
=
nr_getsockopt
,
.
sendmsg
=
nr_sendmsg
,
.
sendmsg
=
nr_sendmsg
,
.
recvmsg
=
nr_recvmsg
,
.
recvmsg
=
nr_recvmsg
,
.
mmap
=
sock_no_mmap
,
.
mmap
=
sock_no_mmap
,
.
sendpage
=
sock_no_sendpage
,
.
sendpage
=
sock_no_sendpage
,
};
};
#include <linux/smp_lock.h>
SOCKOPS_WRAP
(
nr_proto
,
PF_NETROM
);
static
struct
notifier_block
nr_dev_notifier
=
{
static
struct
notifier_block
nr_dev_notifier
=
{
.
notifier_call
=
nr_device_event
,
.
notifier_call
=
nr_device_event
,
};
};
static
struct
net_device
*
dev_nr
;
static
struct
net_device
*
dev_nr
;
...
...
net/netrom/nr_dev.c
View file @
b331768e
/*
/*
* 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
* Copyright 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.
*
* 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.
*/
*/
#include <linux/config.h>
#include <linux/config.h>
#define __NO_VERSION__
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/module.h>
...
@@ -115,7 +103,7 @@ static int nr_rebuild_header(struct sk_buff *skb)
...
@@ -115,7 +103,7 @@ static int nr_rebuild_header(struct sk_buff *skb)
kfree_skb
(
skb
);
kfree_skb
(
skb
);
len
=
skbn
->
len
;
len
=
skbn
->
len
;
if
(
!
nr_route_frame
(
skbn
,
NULL
))
{
if
(
!
nr_route_frame
(
skbn
,
NULL
))
{
kfree_skb
(
skbn
);
kfree_skb
(
skbn
);
stats
->
tx_errors
++
;
stats
->
tx_errors
++
;
...
...
net/netrom/nr_in.c
View file @
b331768e
/*
/*
* 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
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*
* Copyright Darryl Miles G7LED (dlm@g7led.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
* 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.
*/
*/
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
...
@@ -77,7 +60,7 @@ static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
...
@@ -77,7 +60,7 @@ static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
kfree_skb
(
skbo
);
kfree_skb
(
skbo
);
}
}
nr
->
fraglen
=
0
;
nr
->
fraglen
=
0
;
}
}
return
sock_queue_rcv_skb
(
sk
,
skbn
);
return
sock_queue_rcv_skb
(
sk
,
skbn
);
...
@@ -88,36 +71,36 @@ static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
...
@@ -88,36 +71,36 @@ 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.
* The handling of the timer(s) is in file nr_timer.c.
* Handling of state 0 and connection release is in netrom.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
)
{
switch
(
frametype
)
{
case
NR_CONNACK
:
{
nr_cb
*
nr
=
nr_sk
(
sk
);
nr_stop_t1timer
(
sk
);
nr_start_idletimer
(
sk
);
nr
->
your_index
=
skb
->
data
[
17
];
nr
->
your_id
=
skb
->
data
[
18
];
nr
->
vs
=
0
;
nr
->
va
=
0
;
nr
->
vr
=
0
;
nr
->
vl
=
0
;
nr
->
state
=
NR_STATE_3
;
nr
->
n2count
=
0
;
nr
->
window
=
skb
->
data
[
20
];
sk
->
state
=
TCP_ESTABLISHED
;
if
(
!
sk
->
dead
)
sk
->
state_change
(
sk
);
break
;
}
case
NR_CONNACK
:
{
case
NR_CONNACK
|
NR_CHOKE_FLAG
:
nr_cb
*
nr
=
nr_sk
(
sk
);
nr_disconnect
(
sk
,
ECONNREFUSED
);
break
;
nr_stop_t1timer
(
sk
);
nr_start_idletimer
(
sk
);
nr
->
your_index
=
skb
->
data
[
17
];
nr
->
your_id
=
skb
->
data
[
18
];
nr
->
vs
=
0
;
nr
->
va
=
0
;
nr
->
vr
=
0
;
nr
->
vl
=
0
;
nr
->
state
=
NR_STATE_3
;
nr
->
n2count
=
0
;
nr
->
window
=
skb
->
data
[
20
];
sk
->
state
=
TCP_ESTABLISHED
;
if
(
!
sk
->
dead
)
sk
->
state_change
(
sk
);
break
;
}
case
NR_CONNACK
|
NR_CHOKE_FLAG
:
nr_disconnect
(
sk
,
ECONNREFUSED
);
break
;
default:
default:
break
;
break
;
}
}
return
0
;
return
0
;
...
@@ -128,23 +111,23 @@ static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype
...
@@ -128,23 +111,23 @@ 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
* The handling of the timer(s) is in file nr_timer.c
* Handling of state 0 and connection release is in netrom.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
)
{
switch
(
frametype
)
{
case
NR_CONNACK
|
NR_CHOKE_FLAG
:
nr_disconnect
(
sk
,
ECONNRESET
);
break
;
case
NR_CONNACK
|
NR_CHOKE_FLAG
:
case
NR_DISCREQ
:
nr_disconnect
(
sk
,
ECONNRESET
);
nr_write_internal
(
sk
,
NR_DISCACK
);
break
;
case
NR_DISCREQ
:
nr_write_internal
(
sk
,
NR_DISCACK
);
case
NR_DISCACK
:
case
NR_DISCACK
:
nr_disconnect
(
sk
,
0
);
nr_disconnect
(
sk
,
0
);
break
;
break
;
default:
default:
break
;
break
;
}
}
return
0
;
return
0
;
...
@@ -168,35 +151,62 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
...
@@ -168,35 +151,62 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
ns
=
skb
->
data
[
17
];
ns
=
skb
->
data
[
17
];
switch
(
frametype
)
{
switch
(
frametype
)
{
case
NR_CONNREQ
:
case
NR_CONNREQ
:
nr_write_internal
(
sk
,
NR_CONNACK
);
nr_write_internal
(
sk
,
NR_CONNACK
);
break
;
break
;
case
NR_DISCREQ
:
case
NR_DISCREQ
:
nr_write_internal
(
sk
,
NR_DISCACK
);
nr_write_internal
(
sk
,
NR_DISCACK
);
nr_disconnect
(
sk
,
0
);
nr_disconnect
(
sk
,
0
);
break
;
break
;
case
NR_CONNACK
|
NR_CHOKE_FLAG
:
case
NR_CONNACK
|
NR_CHOKE_FLAG
:
case
NR_DISCACK
:
case
NR_DISCACK
:
nr_disconnect
(
sk
,
ECONNRESET
);
nr_disconnect
(
sk
,
ECONNRESET
);
break
;
case
NR_INFOACK
:
case
NR_INFOACK
|
NR_CHOKE_FLAG
:
case
NR_INFOACK
|
NR_NAK_FLAG
:
case
NR_INFOACK
|
NR_NAK_FLAG
|
NR_CHOKE_FLAG
:
if
(
frametype
&
NR_CHOKE_FLAG
)
{
nrom
->
condition
|=
NR_COND_PEER_RX_BUSY
;
nr_start_t4timer
(
sk
);
}
else
{
nrom
->
condition
&=
~
NR_COND_PEER_RX_BUSY
;
nr_stop_t4timer
(
sk
);
}
if
(
!
nr_validate_nr
(
sk
,
nr
))
{
break
;
break
;
}
case
NR_INFOACK
:
if
(
frametype
&
NR_NAK_FLAG
)
{
case
NR_INFOACK
|
NR_CHOKE_FLAG
:
nr_frames_acked
(
sk
,
nr
);
case
NR_INFOACK
|
NR_NAK_FLAG
:
nr_send_nak_frame
(
sk
);
case
NR_INFOACK
|
NR_NAK_FLAG
|
NR_CHOKE_FLAG
:
}
else
{
if
(
frametype
&
NR_CHOKE_FLAG
)
{
if
(
nrom
->
condition
&
NR_COND_PEER_RX_BUSY
)
{
nrom
->
condition
|=
NR_COND_PEER_RX_BUSY
;
nr_frames_acked
(
sk
,
nr
);
nr_start_t4timer
(
sk
);
}
else
{
}
else
{
nrom
->
condition
&=
~
NR_COND_PEER_RX_BUSY
;
nr_check_iframes_acked
(
sk
,
nr
);
nr_stop_t4timer
(
sk
);
}
if
(
!
nr_validate_nr
(
sk
,
nr
))
{
break
;
}
}
}
break
;
case
NR_INFO
:
case
NR_INFO
|
NR_NAK_FLAG
:
case
NR_INFO
|
NR_CHOKE_FLAG
:
case
NR_INFO
|
NR_MORE_FLAG
:
case
NR_INFO
|
NR_NAK_FLAG
|
NR_CHOKE_FLAG
:
case
NR_INFO
|
NR_CHOKE_FLAG
|
NR_MORE_FLAG
:
case
NR_INFO
|
NR_NAK_FLAG
|
NR_MORE_FLAG
:
case
NR_INFO
|
NR_NAK_FLAG
|
NR_CHOKE_FLAG
|
NR_MORE_FLAG
:
if
(
frametype
&
NR_CHOKE_FLAG
)
{
nrom
->
condition
|=
NR_COND_PEER_RX_BUSY
;
nr_start_t4timer
(
sk
);
}
else
{
nrom
->
condition
&=
~
NR_COND_PEER_RX_BUSY
;
nr_stop_t4timer
(
sk
);
}
if
(
nr_validate_nr
(
sk
,
nr
))
{
if
(
frametype
&
NR_NAK_FLAG
)
{
if
(
frametype
&
NR_NAK_FLAG
)
{
nr_frames_acked
(
sk
,
nr
);
nr_frames_acked
(
sk
,
nr
);
nr_send_nak_frame
(
sk
);
nr_send_nak_frame
(
sk
);
...
@@ -207,76 +217,48 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
...
@@ -207,76 +217,48 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
nr_check_iframes_acked
(
sk
,
nr
);
nr_check_iframes_acked
(
sk
,
nr
);
}
}
}
}
}
queued
=
1
;
skb_queue_head
(
&
nrom
->
reseq_queue
,
skb
);
if
(
nrom
->
condition
&
NR_COND_OWN_RX_BUSY
)
break
;
break
;
skb_queue_head_init
(
&
temp_queue
);
case
NR_INFO
:
do
{
case
NR_INFO
|
NR_NAK_FLAG
:
save_vr
=
nrom
->
vr
;
case
NR_INFO
|
NR_CHOKE_FLAG
:
while
((
skbn
=
skb_dequeue
(
&
nrom
->
reseq_queue
))
!=
NULL
)
{
case
NR_INFO
|
NR_MORE_FLAG
:
ns
=
skbn
->
data
[
17
];
case
NR_INFO
|
NR_NAK_FLAG
|
NR_CHOKE_FLAG
:
if
(
ns
==
nrom
->
vr
)
{
case
NR_INFO
|
NR_CHOKE_FLAG
|
NR_MORE_FLAG
:
if
(
nr_queue_rx_frame
(
sk
,
skbn
,
frametype
&
NR_MORE_FLAG
)
==
0
)
{
case
NR_INFO
|
NR_NAK_FLAG
|
NR_MORE_FLAG
:
nrom
->
vr
=
(
nrom
->
vr
+
1
)
%
NR_MODULUS
;
case
NR_INFO
|
NR_NAK_FLAG
|
NR_CHOKE_FLAG
|
NR_MORE_FLAG
:
if
(
frametype
&
NR_CHOKE_FLAG
)
{
nrom
->
condition
|=
NR_COND_PEER_RX_BUSY
;
nr_start_t4timer
(
sk
);
}
else
{
nrom
->
condition
&=
~
NR_COND_PEER_RX_BUSY
;
nr_stop_t4timer
(
sk
);
}
if
(
nr_validate_nr
(
sk
,
nr
))
{
if
(
frametype
&
NR_NAK_FLAG
)
{
nr_frames_acked
(
sk
,
nr
);
nr_send_nak_frame
(
sk
);
}
else
{
if
(
nrom
->
condition
&
NR_COND_PEER_RX_BUSY
)
{
nr_frames_acked
(
sk
,
nr
);
}
else
{
}
else
{
nr_check_iframes_acked
(
sk
,
nr
);
nrom
->
condition
|=
NR_COND_OWN_RX_BUSY
;
}
}
}
queued
=
1
;
skb_queue_head
(
&
nrom
->
reseq_queue
,
skb
);
if
(
nrom
->
condition
&
NR_COND_OWN_RX_BUSY
)
break
;
skb_queue_head_init
(
&
temp_queue
);
do
{
save_vr
=
nrom
->
vr
;
while
((
skbn
=
skb_dequeue
(
&
nrom
->
reseq_queue
))
!=
NULL
)
{
ns
=
skbn
->
data
[
17
];
if
(
ns
==
nrom
->
vr
)
{
if
(
nr_queue_rx_frame
(
sk
,
skbn
,
frametype
&
NR_MORE_FLAG
)
==
0
)
{
nrom
->
vr
=
(
nrom
->
vr
+
1
)
%
NR_MODULUS
;
}
else
{
nrom
->
condition
|=
NR_COND_OWN_RX_BUSY
;
skb_queue_tail
(
&
temp_queue
,
skbn
);
}
}
else
if
(
nr_in_rx_window
(
sk
,
ns
))
{
skb_queue_tail
(
&
temp_queue
,
skbn
);
skb_queue_tail
(
&
temp_queue
,
skbn
);
}
else
{
kfree_skb
(
skbn
);
}
}
}
}
else
if
(
nr_in_rx_window
(
sk
,
ns
))
{
while
((
skbn
=
skb_dequeue
(
&
temp_queue
))
!=
NULL
)
{
skb_queue_tail
(
&
temp_queue
,
skbn
);
skb_queue_tail
(
&
nrom
->
reseq_queue
,
skbn
);
}
else
{
}
kfree_skb
(
skbn
);
}
while
(
save_vr
!=
nrom
->
vr
);
/*
* Window is full, ack it immediately.
*/
if
(((
nrom
->
vl
+
nrom
->
window
)
%
NR_MODULUS
)
==
nrom
->
vr
)
{
nr_enquiry_response
(
sk
);
}
else
{
if
(
!
(
nrom
->
condition
&
NR_COND_ACK_PENDING
))
{
nrom
->
condition
|=
NR_COND_ACK_PENDING
;
nr_start_t2timer
(
sk
);
}
}
}
}
break
;
while
((
skbn
=
skb_dequeue
(
&
temp_queue
))
!=
NULL
)
{
skb_queue_tail
(
&
nrom
->
reseq_queue
,
skbn
);
}
}
while
(
save_vr
!=
nrom
->
vr
);
/*
* Window is full, ack it immediately.
*/
if
(((
nrom
->
vl
+
nrom
->
window
)
%
NR_MODULUS
)
==
nrom
->
vr
)
{
nr_enquiry_response
(
sk
);
}
else
{
if
(
!
(
nrom
->
condition
&
NR_COND_ACK_PENDING
))
{
nrom
->
condition
|=
NR_COND_ACK_PENDING
;
nr_start_t2timer
(
sk
);
}
}
break
;
default:
default:
break
;
break
;
}
}
return
queued
;
return
queued
;
...
@@ -294,15 +276,15 @@ int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb)
...
@@ -294,15 +276,15 @@ int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb)
frametype
=
skb
->
data
[
19
];
frametype
=
skb
->
data
[
19
];
switch
(
nr
->
state
)
{
switch
(
nr
->
state
)
{
case
NR_STATE_1
:
case
NR_STATE_1
:
queued
=
nr_state1_machine
(
sk
,
skb
,
frametype
);
queued
=
nr_state1_machine
(
sk
,
skb
,
frametype
);
break
;
break
;
case
NR_STATE_2
:
case
NR_STATE_2
:
queued
=
nr_state2_machine
(
sk
,
skb
,
frametype
);
queued
=
nr_state2_machine
(
sk
,
skb
,
frametype
);
break
;
break
;
case
NR_STATE_3
:
case
NR_STATE_3
:
queued
=
nr_state3_machine
(
sk
,
skb
,
frametype
);
queued
=
nr_state3_machine
(
sk
,
skb
,
frametype
);
break
;
break
;
}
}
nr_kick
(
sk
);
nr_kick
(
sk
);
...
...
net/netrom/nr_loopback.c
View file @
b331768e
/*
/*
* 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
* This code REQUIRES 2.1.15 or higher/ NET3.038
* the Free Software Foundation; either version 2 of the License, or
*
* (at your option) any later version.
* 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().
*
*
* Copyright Tomi Manninen OH2BNS (oh2bns@sral.fi)
*/
*/
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
#include <linux/timer.h>
#include <linux/timer.h>
...
...
net/netrom/nr_out.c
View file @
b331768e
/*
/*
* 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
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*
* Copyright Darryl Miles G7LED (dlm@g7led.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.
*
* 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.
*/
*/
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
...
@@ -85,7 +76,7 @@ void nr_output(struct sock *sk, struct sk_buff *skb)
...
@@ -85,7 +76,7 @@ void nr_output(struct sock *sk, struct sk_buff *skb)
nr_kick
(
sk
);
nr_kick
(
sk
);
}
}
/*
/*
* This procedure is passed a buffer descriptor for an iframe. It builds
* This procedure is passed a buffer descriptor for an iframe. It builds
* the rest of the control part of the frame and then writes it out.
* the rest of the control part of the frame and then writes it out.
*/
*/
...
@@ -104,7 +95,7 @@ static void nr_send_iframe(struct sock *sk, struct sk_buff *skb)
...
@@ -104,7 +95,7 @@ static void nr_send_iframe(struct sock *sk, struct sk_buff *skb)
nr_start_idletimer
(
sk
);
nr_start_idletimer
(
sk
);
nr_transmit_buffer
(
sk
,
skb
);
nr_transmit_buffer
(
sk
,
skb
);
}
}
void
nr_send_nak_frame
(
struct
sock
*
sk
)
void
nr_send_nak_frame
(
struct
sock
*
sk
)
...
...
net/netrom/nr_route.c
View file @
b331768e
/*
/*
* 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
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*
* Copyright Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* This module:
* Copyright Tomi Manninen OH2BNS (oh2bns@sral.fi)
* 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.
*/
*/
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
...
@@ -47,12 +34,15 @@
...
@@ -47,12 +34,15 @@
#include <linux/notifier.h>
#include <linux/notifier.h>
#include <linux/netfilter.h>
#include <linux/netfilter.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <net/netrom.h>
#include <net/netrom.h>
static
unsigned
int
nr_neigh_no
=
1
;
static
unsigned
int
nr_neigh_no
=
1
;
static
struct
nr_node
*
nr_node_list
;
static
struct
nr_node
*
nr_node_list
;
static
spinlock_t
nr_node_lock
;
static
struct
nr_neigh
*
nr_neigh_list
;
static
struct
nr_neigh
*
nr_neigh_list
;
static
spinlock_t
nr_neigh_lock
;
static
void
nr_remove_neigh
(
struct
nr_neigh
*
);
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
...
@@ -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_node
*
nr_node
;
struct
nr_neigh
*
nr_neigh
;
struct
nr_neigh
*
nr_neigh
;
struct
nr_route
nr_route
;
struct
nr_route
nr_route
;
unsigned
long
flags
;
int
i
,
found
;
int
i
,
found
;
if
(
nr_dev_get
(
nr
)
!=
NULL
)
/* Can't add routes to ourself */
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
...
@@ -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
));
memcpy
(
nr_neigh
->
digipeat
,
ax25_digi
,
sizeof
(
ax25_digi
));
}
}
save_flags
(
flags
);
spin_lock_bh
(
&
nr_neigh_lock
);
cli
();
nr_neigh
->
next
=
nr_neigh_list
;
nr_neigh
->
next
=
nr_neigh_list
;
nr_neigh_list
=
nr_neigh
;
nr_neigh_list
=
nr_neigh
;
spin_unlock_bh
(
&
nr_neigh_lock
);
restore_flags
(
flags
);
}
}
if
(
quality
!=
0
&&
ax25cmp
(
nr
,
ax25
)
==
0
&&
!
nr_neigh
->
locked
)
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
...
@@ -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
].
obs_count
=
obs_count
;
nr_node
->
routes
[
0
].
neighbour
=
nr_neigh
;
nr_node
->
routes
[
0
].
neighbour
=
nr_neigh
;
save_flags
(
flags
);
spin_lock_bh
(
&
nr_node_lock
);
cli
();
nr_node
->
next
=
nr_node_list
;
nr_node
->
next
=
nr_node_list
;
nr_node_list
=
nr_node
;
nr_node_list
=
nr_node
;
spin_unlock_bh
(
&
nr_node_lock
);
restore_flags
(
flags
);
nr_neigh
->
count
++
;
nr_neigh
->
count
++
;
...
@@ -207,40 +190,49 @@ static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax2
...
@@ -207,40 +190,49 @@ static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax2
/* Now re-sort the routes in quality order */
/* Now re-sort the routes in quality order */
switch
(
nr_node
->
count
)
{
switch
(
nr_node
->
count
)
{
case
3
:
case
3
:
if
(
nr_node
->
routes
[
1
].
quality
>
nr_node
->
routes
[
0
].
quality
)
{
if
(
nr_node
->
routes
[
1
].
quality
>
nr_node
->
routes
[
0
].
quality
)
{
switch
(
nr_node
->
which
)
{
switch
(
nr_node
->
which
)
{
case
0
:
nr_node
->
which
=
1
;
break
;
case
0
:
nr_node
->
which
=
1
;
break
;
case
1
:
nr_node
->
which
=
0
;
break
;
case
1
:
nr_node
->
which
=
0
;
break
;
default:
break
;
default:
break
;
}
nr_route
=
nr_node
->
routes
[
0
];
nr_node
->
routes
[
0
]
=
nr_node
->
routes
[
1
];
nr_node
->
routes
[
1
]
=
nr_route
;
}
}
if
(
nr_node
->
routes
[
2
].
quality
>
nr_node
->
routes
[
1
].
quality
)
{
nr_route
=
nr_node
->
routes
[
0
];
switch
(
nr_node
->
which
)
{
nr_node
->
routes
[
0
]
=
nr_node
->
routes
[
1
];
case
1
:
nr_node
->
which
=
2
;
break
;
nr_node
->
routes
[
1
]
=
nr_route
;
case
2
:
nr_node
->
which
=
1
;
break
;
}
default:
break
;
if
(
nr_node
->
routes
[
2
].
quality
>
nr_node
->
routes
[
1
].
quality
)
{
}
switch
(
nr_node
->
which
)
{
nr_route
=
nr_node
->
routes
[
1
];
case
1
:
nr_node
->
which
=
2
;
nr_node
->
routes
[
1
]
=
nr_node
->
routes
[
2
];
break
;
nr_node
->
routes
[
2
]
=
nr_route
;
case
2
:
nr_node
->
which
=
1
;
break
;
default:
break
;
}
}
case
2
:
nr_route
=
nr_node
->
routes
[
1
];
if
(
nr_node
->
routes
[
1
].
quality
>
nr_node
->
routes
[
0
].
quality
)
{
nr_node
->
routes
[
1
]
=
nr_node
->
routes
[
2
];
switch
(
nr_node
->
which
)
{
nr_node
->
routes
[
2
]
=
nr_route
;
case
0
:
nr_node
->
which
=
1
;
break
;
}
case
1
:
nr_node
->
which
=
0
;
break
;
case
2
:
default:
break
;
if
(
nr_node
->
routes
[
1
].
quality
>
nr_node
->
routes
[
0
].
quality
)
{
}
switch
(
nr_node
->
which
)
{
nr_route
=
nr_node
->
routes
[
0
];
case
0
:
nr_node
->
which
=
1
;
nr_node
->
routes
[
0
]
=
nr_node
->
routes
[
1
];
break
;
nr_node
->
routes
[
1
]
=
nr_route
;
case
1
:
nr_node
->
which
=
0
;
break
;
default:
break
;
}
}
case
1
:
nr_route
=
nr_node
->
routes
[
0
];
break
;
nr_node
->
routes
[
0
]
=
nr_node
->
routes
[
1
];
nr_node
->
routes
[
1
]
=
nr_route
;
}
case
1
:
break
;
}
}
for
(
i
=
0
;
i
<
nr_node
->
count
;
i
++
)
{
for
(
i
=
0
;
i
<
nr_node
->
count
;
i
++
)
{
...
@@ -257,14 +249,11 @@ static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax2
...
@@ -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
)
static
void
nr_remove_node
(
struct
nr_node
*
nr_node
)
{
{
struct
nr_node
*
s
;
struct
nr_node
*
s
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
nr_node_lock
);
if
((
s
=
nr_node_list
)
==
nr_node
)
{
if
((
s
=
nr_node_list
)
==
nr_node
)
{
nr_node_list
=
nr_node
->
next
;
nr_node_list
=
nr_node
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_node_lock
);
kfree
(
nr_node
);
kfree
(
nr_node
);
return
;
return
;
}
}
...
@@ -272,7 +261,7 @@ static void nr_remove_node(struct nr_node *nr_node)
...
@@ -272,7 +261,7 @@ static void nr_remove_node(struct nr_node *nr_node)
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
if
(
s
->
next
==
nr_node
)
{
if
(
s
->
next
==
nr_node
)
{
s
->
next
=
nr_node
->
next
;
s
->
next
=
nr_node
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_node_lock
);
kfree
(
nr_node
);
kfree
(
nr_node
);
return
;
return
;
}
}
...
@@ -280,20 +269,17 @@ static void nr_remove_node(struct nr_node *nr_node)
...
@@ -280,20 +269,17 @@ static void nr_remove_node(struct nr_node *nr_node)
s
=
s
->
next
;
s
=
s
->
next
;
}
}
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_node_lock
);
}
}
static
void
nr_remove_neigh
(
struct
nr_neigh
*
nr_neigh
)
static
void
nr_remove_neigh
(
struct
nr_neigh
*
nr_neigh
)
{
{
struct
nr_neigh
*
s
;
struct
nr_neigh
*
s
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
nr_neigh_lock
);
if
((
s
=
nr_neigh_list
)
==
nr_neigh
)
{
if
((
s
=
nr_neigh_list
)
==
nr_neigh
)
{
nr_neigh_list
=
nr_neigh
->
next
;
nr_neigh_list
=
nr_neigh
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_neigh_lock
);
if
(
nr_neigh
->
digipeat
!=
NULL
)
if
(
nr_neigh
->
digipeat
!=
NULL
)
kfree
(
nr_neigh
->
digipeat
);
kfree
(
nr_neigh
->
digipeat
);
kfree
(
nr_neigh
);
kfree
(
nr_neigh
);
...
@@ -303,7 +289,7 @@ static void nr_remove_neigh(struct nr_neigh *nr_neigh)
...
@@ -303,7 +289,7 @@ static void nr_remove_neigh(struct nr_neigh *nr_neigh)
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
if
(
s
->
next
==
nr_neigh
)
{
if
(
s
->
next
==
nr_neigh
)
{
s
->
next
=
nr_neigh
->
next
;
s
->
next
=
nr_neigh
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
nr_neigh_lock
);
if
(
nr_neigh
->
digipeat
!=
NULL
)
if
(
nr_neigh
->
digipeat
!=
NULL
)
kfree
(
nr_neigh
->
digipeat
);
kfree
(
nr_neigh
->
digipeat
);
kfree
(
nr_neigh
);
kfree
(
nr_neigh
);
...
@@ -312,8 +298,7 @@ static void nr_remove_neigh(struct nr_neigh *nr_neigh)
...
@@ -312,8 +298,7 @@ static void nr_remove_neigh(struct nr_neigh *nr_neigh)
s
=
s
->
next
;
s
=
s
->
next
;
}
}
spin_unlock_bh
(
&
nr_neigh_lock
);
restore_flags
(
flags
);
}
}
/*
/*
...
@@ -330,13 +315,15 @@ static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct n
...
@@ -330,13 +315,15 @@ static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct n
if
(
ax25cmp
(
callsign
,
&
nr_node
->
callsign
)
==
0
)
if
(
ax25cmp
(
callsign
,
&
nr_node
->
callsign
)
==
0
)
break
;
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
)
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
)
if
(
ax25cmp
(
neighbour
,
&
nr_neigh
->
callsign
)
==
0
&&
nr_neigh
->
dev
==
dev
)
break
;
break
;
if
(
nr_neigh
==
NULL
)
return
-
EINVAL
;
if
(
nr_neigh
==
NULL
)
return
-
EINVAL
;
for
(
i
=
0
;
i
<
nr_node
->
count
;
i
++
)
{
for
(
i
=
0
;
i
<
nr_node
->
count
;
i
++
)
{
if
(
nr_node
->
routes
[
i
].
neighbour
==
nr_neigh
)
{
if
(
nr_node
->
routes
[
i
].
neighbour
==
nr_neigh
)
{
...
@@ -351,12 +338,12 @@ static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct n
...
@@ -351,12 +338,12 @@ static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct n
nr_remove_node
(
nr_node
);
nr_remove_node
(
nr_node
);
}
else
{
}
else
{
switch
(
i
)
{
switch
(
i
)
{
case
0
:
case
0
:
nr_node
->
routes
[
0
]
=
nr_node
->
routes
[
1
];
nr_node
->
routes
[
0
]
=
nr_node
->
routes
[
1
];
case
1
:
case
1
:
nr_node
->
routes
[
1
]
=
nr_node
->
routes
[
2
];
nr_node
->
routes
[
1
]
=
nr_node
->
routes
[
2
];
case
2
:
case
2
:
break
;
break
;
}
}
}
}
...
@@ -373,7 +360,6 @@ static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct n
...
@@ -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
)
static
int
nr_add_neigh
(
ax25_address
*
callsign
,
ax25_digi
*
ax25_digi
,
struct
net_device
*
dev
,
unsigned
int
quality
)
{
{
struct
nr_neigh
*
nr_neigh
;
struct
nr_neigh
*
nr_neigh
;
unsigned
long
flags
;
for
(
nr_neigh
=
nr_neigh_list
;
nr_neigh
!=
NULL
;
nr_neigh
=
nr_neigh
->
next
)
{
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
)
{
if
(
ax25cmp
(
callsign
,
&
nr_neigh
->
callsign
)
==
0
&&
nr_neigh
->
dev
==
dev
)
{
...
@@ -404,15 +390,12 @@ static int nr_add_neigh(ax25_address *callsign, ax25_digi *ax25_digi, struct net
...
@@ -404,15 +390,12 @@ static int nr_add_neigh(ax25_address *callsign, ax25_digi *ax25_digi, struct net
memcpy
(
nr_neigh
->
digipeat
,
ax25_digi
,
sizeof
(
ax25_digi
));
memcpy
(
nr_neigh
->
digipeat
,
ax25_digi
,
sizeof
(
ax25_digi
));
}
}
save_flags
(
flags
);
spin_lock_bh
(
&
nr_neigh_lock
);
cli
();
nr_neigh
->
next
=
nr_neigh_list
;
nr_neigh
->
next
=
nr_neigh_list
;
nr_neigh_list
=
nr_neigh
;
nr_neigh_list
=
nr_neigh
;
spin_unlock_bh
(
&
nr_neigh_lock
);
restore_flags
(
flags
);
return
0
;
return
0
;
}
}
/*
/*
...
@@ -457,7 +440,6 @@ static int nr_dec_obs(void)
...
@@ -457,7 +440,6 @@ static int nr_dec_obs(void)
for
(
i
=
0
;
i
<
s
->
count
;
i
++
)
{
for
(
i
=
0
;
i
<
s
->
count
;
i
++
)
{
switch
(
s
->
routes
[
i
].
obs_count
)
{
switch
(
s
->
routes
[
i
].
obs_count
)
{
case
0
:
/* A locked entry */
case
0
:
/* A locked entry */
break
;
break
;
...
@@ -520,12 +502,12 @@ void nr_rt_device_down(struct net_device *dev)
...
@@ -520,12 +502,12 @@ void nr_rt_device_down(struct net_device *dev)
t
->
count
--
;
t
->
count
--
;
switch
(
i
)
{
switch
(
i
)
{
case
0
:
case
0
:
t
->
routes
[
0
]
=
t
->
routes
[
1
];
t
->
routes
[
0
]
=
t
->
routes
[
1
];
case
1
:
case
1
:
t
->
routes
[
1
]
=
t
->
routes
[
2
];
t
->
routes
[
1
]
=
t
->
routes
[
2
];
case
2
:
case
2
:
break
;
break
;
}
}
}
}
}
}
...
@@ -622,51 +604,50 @@ int nr_rt_ioctl(unsigned int cmd, void *arg)
...
@@ -622,51 +604,50 @@ int nr_rt_ioctl(unsigned int cmd, void *arg)
struct
net_device
*
dev
;
struct
net_device
*
dev
;
switch
(
cmd
)
{
switch
(
cmd
)
{
case
SIOCADDRT
:
if
(
copy_from_user
(
&
nr_route
,
arg
,
sizeof
(
struct
nr_route_struct
)))
return
-
EFAULT
;
if
((
dev
=
nr_ax25_dev_get
(
nr_route
.
device
))
==
NULL
)
return
-
EINVAL
;
if
(
nr_route
.
ndigis
<
0
||
nr_route
.
ndigis
>
AX25_MAX_DIGIS
)
return
-
EINVAL
;
switch
(
nr_route
.
type
)
{
case
NETROM_NODE
:
return
nr_add_node
(
&
nr_route
.
callsign
,
nr_route
.
mnemonic
,
&
nr_route
.
neighbour
,
nr_call_to_digi
(
nr_route
.
ndigis
,
nr_route
.
digipeaters
),
dev
,
nr_route
.
quality
,
nr_route
.
obs_count
);
case
NETROM_NEIGH
:
return
nr_add_neigh
(
&
nr_route
.
callsign
,
nr_call_to_digi
(
nr_route
.
ndigis
,
nr_route
.
digipeaters
),
dev
,
nr_route
.
quality
);
default:
return
-
EINVAL
;
}
case
SIOCADDRT
:
case
SIOCDELRT
:
if
(
copy_from_user
(
&
nr_route
,
arg
,
sizeof
(
struct
nr_route_struct
)))
if
(
copy_from_user
(
&
nr_route
,
arg
,
sizeof
(
struct
nr_route_struct
)))
return
-
EFAULT
;
return
-
EFAULT
;
if
((
dev
=
nr_ax25_dev_get
(
nr_route
.
device
))
==
NULL
)
if
((
dev
=
nr_ax25_dev_get
(
nr_route
.
device
))
==
NULL
)
return
-
EINVAL
;
return
-
EINVAL
;
if
(
nr_route
.
ndigis
<
0
||
nr_route
.
ndigis
>
AX25_MAX_DIGIS
)
switch
(
nr_route
.
type
)
{
return
-
EINVAL
;
case
NETROM_NODE
:
switch
(
nr_route
.
type
)
{
return
nr_del_node
(
&
nr_route
.
callsign
,
case
NETROM_NODE
:
&
nr_route
.
neighbour
,
dev
);
return
nr_add_node
(
&
nr_route
.
callsign
,
case
NETROM_NEIGH
:
nr_route
.
mnemonic
,
return
nr_del_neigh
(
&
nr_route
.
callsign
,
&
nr_route
.
neighbour
,
dev
,
nr_route
.
quality
);
nr_call_to_digi
(
nr_route
.
ndigis
,
nr_route
.
digipeaters
),
dev
,
nr_route
.
quality
,
nr_route
.
obs_count
);
case
NETROM_NEIGH
:
return
nr_add_neigh
(
&
nr_route
.
callsign
,
nr_call_to_digi
(
nr_route
.
ndigis
,
nr_route
.
digipeaters
),
dev
,
nr_route
.
quality
);
default:
return
-
EINVAL
;
}
case
SIOCDELRT
:
if
(
copy_from_user
(
&
nr_route
,
arg
,
sizeof
(
struct
nr_route_struct
)))
return
-
EFAULT
;
if
((
dev
=
nr_ax25_dev_get
(
nr_route
.
device
))
==
NULL
)
return
-
EINVAL
;
switch
(
nr_route
.
type
)
{
case
NETROM_NODE
:
return
nr_del_node
(
&
nr_route
.
callsign
,
&
nr_route
.
neighbour
,
dev
);
case
NETROM_NEIGH
:
return
nr_del_neigh
(
&
nr_route
.
callsign
,
dev
,
nr_route
.
quality
);
default:
return
-
EINVAL
;
}
case
SIOCNRDECOBS
:
return
nr_dec_obs
();
default:
default:
return
-
EINVAL
;
return
-
EINVAL
;
}
case
SIOCNRDECOBS
:
return
nr_dec_obs
();
default:
return
-
EINVAL
;
}
}
return
0
;
return
0
;
...
@@ -758,8 +739,7 @@ int nr_nodes_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -758,8 +739,7 @@ int nr_nodes_get_info(char *buffer, char **start, off_t offset, int length)
off_t
begin
=
0
;
off_t
begin
=
0
;
int
i
;
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
"
);
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
)
{
for
(
nr_node
=
nr_node_list
;
nr_node
!=
NULL
;
nr_node
=
nr_node
->
next
)
{
...
@@ -767,7 +747,7 @@ int nr_nodes_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -767,7 +747,7 @@ int nr_nodes_get_info(char *buffer, char **start, off_t offset, int length)
ax2asc
(
&
nr_node
->
callsign
),
ax2asc
(
&
nr_node
->
callsign
),
(
nr_node
->
mnemonic
[
0
]
==
'\0'
)
?
"*"
:
nr_node
->
mnemonic
,
(
nr_node
->
mnemonic
[
0
]
==
'\0'
)
?
"*"
:
nr_node
->
mnemonic
,
nr_node
->
which
+
1
,
nr_node
->
which
+
1
,
nr_node
->
count
);
nr_node
->
count
);
for
(
i
=
0
;
i
<
nr_node
->
count
;
i
++
)
{
for
(
i
=
0
;
i
<
nr_node
->
count
;
i
++
)
{
len
+=
sprintf
(
buffer
+
len
,
" %3d %d %05d"
,
len
+=
sprintf
(
buffer
+
len
,
" %3d %d %05d"
,
...
@@ -788,8 +768,7 @@ int nr_nodes_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -788,8 +768,7 @@ int nr_nodes_get_info(char *buffer, char **start, off_t offset, int length)
if
(
pos
>
offset
+
length
)
if
(
pos
>
offset
+
length
)
break
;
break
;
}
}
spin_unlock_bh
(
&
nr_node_lock
);
sti
();
*
start
=
buffer
+
(
offset
-
begin
);
*
start
=
buffer
+
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
...
@@ -797,7 +776,7 @@ int nr_nodes_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -797,7 +776,7 @@ int nr_nodes_get_info(char *buffer, char **start, off_t offset, int length)
if
(
len
>
length
)
len
=
length
;
if
(
len
>
length
)
len
=
length
;
return
len
;
return
len
;
}
}
int
nr_neigh_get_info
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
int
nr_neigh_get_info
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
{
{
...
@@ -807,8 +786,7 @@ int nr_neigh_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -807,8 +786,7 @@ int nr_neigh_get_info(char *buffer, char **start, off_t offset, int length)
off_t
begin
=
0
;
off_t
begin
=
0
;
int
i
;
int
i
;
cli
();
spin_lock_bh
(
&
nr_neigh_lock
);
len
+=
sprintf
(
buffer
,
"addr callsign dev qual lock count failed digipeaters
\n
"
);
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
)
{
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)
...
@@ -839,7 +817,7 @@ int nr_neigh_get_info(char *buffer, char **start, off_t offset, int length)
break
;
break
;
}
}
s
ti
(
);
s
pin_unlock_bh
(
&
nr_neigh_lock
);
*
start
=
buffer
+
(
offset
-
begin
);
*
start
=
buffer
+
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
...
@@ -847,7 +825,7 @@ int nr_neigh_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -847,7 +825,7 @@ int nr_neigh_get_info(char *buffer, char **start, off_t offset, int length)
if
(
len
>
length
)
len
=
length
;
if
(
len
>
length
)
len
=
length
;
return
len
;
return
len
;
}
}
/*
/*
* Free all memory associated with the nodes and routes lists.
* Free all memory associated with the nodes and routes lists.
...
...
net/netrom/nr_subr.c
View file @
b331768e
/*
/*
* 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
* Copyright 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.
*
* 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.
*/
*/
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
...
@@ -125,7 +116,7 @@ int nr_in_rx_window(struct sock *sk, unsigned short ns)
...
@@ -125,7 +116,7 @@ int nr_in_rx_window(struct sock *sk, unsigned short ns)
return
0
;
return
0
;
}
}
/*
/*
* This routine is called when the HDLC layer internally generates a
* This routine is called when the HDLC layer internally generates a
* control frame.
* control frame.
*/
*/
...
@@ -139,19 +130,19 @@ void nr_write_internal(struct sock *sk, int frametype)
...
@@ -139,19 +130,19 @@ void nr_write_internal(struct sock *sk, int frametype)
len
=
AX25_BPQ_HEADER_LEN
+
AX25_MAX_HEADER_LEN
+
NR_NETWORK_LEN
+
NR_TRANSPORT_LEN
;
len
=
AX25_BPQ_HEADER_LEN
+
AX25_MAX_HEADER_LEN
+
NR_NETWORK_LEN
+
NR_TRANSPORT_LEN
;
switch
(
frametype
&
0x0F
)
{
switch
(
frametype
&
0x0F
)
{
case
NR_CONNREQ
:
case
NR_CONNREQ
:
len
+=
17
;
len
+=
17
;
break
;
break
;
case
NR_CONNACK
:
case
NR_CONNACK
:
len
+=
(
nr
->
bpqext
)
?
2
:
1
;
len
+=
(
nr
->
bpqext
)
?
2
:
1
;
break
;
break
;
case
NR_DISCREQ
:
case
NR_DISCREQ
:
case
NR_DISCACK
:
case
NR_DISCACK
:
case
NR_INFOACK
:
case
NR_INFOACK
:
break
;
break
;
default:
default:
printk
(
KERN_ERR
"NET/ROM: nr_write_internal - invalid frame type %d
\n
"
,
frametype
);
printk
(
KERN_ERR
"NET/ROM: nr_write_internal - invalid frame type %d
\n
"
,
frametype
);
return
;
return
;
}
}
if
((
skb
=
alloc_skb
(
len
,
GFP_ATOMIC
))
==
NULL
)
if
((
skb
=
alloc_skb
(
len
,
GFP_ATOMIC
))
==
NULL
)
...
@@ -161,59 +152,58 @@ void nr_write_internal(struct sock *sk, int frametype)
...
@@ -161,59 +152,58 @@ void nr_write_internal(struct sock *sk, int frametype)
* Space for AX.25 and NET/ROM network header
* Space for AX.25 and NET/ROM network header
*/
*/
skb_reserve
(
skb
,
AX25_BPQ_HEADER_LEN
+
AX25_MAX_HEADER_LEN
+
NR_NETWORK_LEN
);
skb_reserve
(
skb
,
AX25_BPQ_HEADER_LEN
+
AX25_MAX_HEADER_LEN
+
NR_NETWORK_LEN
);
dptr
=
skb_put
(
skb
,
skb_tailroom
(
skb
));
dptr
=
skb_put
(
skb
,
skb_tailroom
(
skb
));
switch
(
frametype
&
0x0F
)
{
switch
(
frametype
&
0x0F
)
{
case
NR_CONNREQ
:
timeout
=
nr
->
t1
/
HZ
;
*
dptr
++
=
nr
->
my_index
;
*
dptr
++
=
nr
->
my_id
;
*
dptr
++
=
0
;
*
dptr
++
=
0
;
*
dptr
++
=
frametype
;
*
dptr
++
=
nr
->
window
;
memcpy
(
dptr
,
&
nr
->
user_addr
,
AX25_ADDR_LEN
);
dptr
[
6
]
&=
~
AX25_CBIT
;
dptr
[
6
]
&=
~
AX25_EBIT
;
dptr
[
6
]
|=
AX25_SSSID_SPARE
;
dptr
+=
AX25_ADDR_LEN
;
memcpy
(
dptr
,
&
nr
->
source_addr
,
AX25_ADDR_LEN
);
dptr
[
6
]
&=
~
AX25_CBIT
;
dptr
[
6
]
&=
~
AX25_EBIT
;
dptr
[
6
]
|=
AX25_SSSID_SPARE
;
dptr
+=
AX25_ADDR_LEN
;
*
dptr
++
=
timeout
%
256
;
*
dptr
++
=
timeout
/
256
;
break
;
case
NR_CONNACK
:
*
dptr
++
=
nr
->
your_index
;
*
dptr
++
=
nr
->
your_id
;
*
dptr
++
=
nr
->
my_index
;
*
dptr
++
=
nr
->
my_id
;
*
dptr
++
=
frametype
;
*
dptr
++
=
nr
->
window
;
if
(
nr
->
bpqext
)
*
dptr
++
=
sysctl_netrom_network_ttl_initialiser
;
break
;
case
NR_DISCREQ
:
case
NR_DISCACK
:
*
dptr
++
=
nr
->
your_index
;
*
dptr
++
=
nr
->
your_id
;
*
dptr
++
=
0
;
*
dptr
++
=
0
;
*
dptr
++
=
frametype
;
break
;
case
NR_CONNREQ
:
case
NR_INFOACK
:
timeout
=
nr
->
t1
/
HZ
;
*
dptr
++
=
nr
->
your_index
;
*
dptr
++
=
nr
->
my_index
;
*
dptr
++
=
nr
->
your_id
;
*
dptr
++
=
nr
->
my_id
;
*
dptr
++
=
0
;
*
dptr
++
=
0
;
*
dptr
++
=
nr
->
vr
;
*
dptr
++
=
0
;
*
dptr
++
=
frametype
;
*
dptr
++
=
frametype
;
break
;
*
dptr
++
=
nr
->
window
;
memcpy
(
dptr
,
&
nr
->
user_addr
,
AX25_ADDR_LEN
);
dptr
[
6
]
&=
~
AX25_CBIT
;
dptr
[
6
]
&=
~
AX25_EBIT
;
dptr
[
6
]
|=
AX25_SSSID_SPARE
;
dptr
+=
AX25_ADDR_LEN
;
memcpy
(
dptr
,
&
nr
->
source_addr
,
AX25_ADDR_LEN
);
dptr
[
6
]
&=
~
AX25_CBIT
;
dptr
[
6
]
&=
~
AX25_EBIT
;
dptr
[
6
]
|=
AX25_SSSID_SPARE
;
dptr
+=
AX25_ADDR_LEN
;
*
dptr
++
=
timeout
%
256
;
*
dptr
++
=
timeout
/
256
;
break
;
case
NR_CONNACK
:
*
dptr
++
=
nr
->
your_index
;
*
dptr
++
=
nr
->
your_id
;
*
dptr
++
=
nr
->
my_index
;
*
dptr
++
=
nr
->
my_id
;
*
dptr
++
=
frametype
;
*
dptr
++
=
nr
->
window
;
if
(
nr
->
bpqext
)
*
dptr
++
=
sysctl_netrom_network_ttl_initialiser
;
break
;
case
NR_DISCREQ
:
case
NR_DISCACK
:
*
dptr
++
=
nr
->
your_index
;
*
dptr
++
=
nr
->
your_id
;
*
dptr
++
=
0
;
*
dptr
++
=
0
;
*
dptr
++
=
frametype
;
break
;
case
NR_INFOACK
:
*
dptr
++
=
nr
->
your_index
;
*
dptr
++
=
nr
->
your_id
;
*
dptr
++
=
0
;
*
dptr
++
=
nr
->
vr
;
*
dptr
++
=
frametype
;
break
;
}
}
nr_transmit_buffer
(
sk
,
skb
);
nr_transmit_buffer
(
sk
,
skb
);
...
@@ -243,7 +233,7 @@ void nr_transmit_refusal(struct sk_buff *skb, int mine)
...
@@ -243,7 +233,7 @@ void nr_transmit_refusal(struct sk_buff *skb, int mine)
dptr
[
6
]
&=
~
AX25_EBIT
;
dptr
[
6
]
&=
~
AX25_EBIT
;
dptr
[
6
]
|=
AX25_SSSID_SPARE
;
dptr
[
6
]
|=
AX25_SSSID_SPARE
;
dptr
+=
AX25_ADDR_LEN
;
dptr
+=
AX25_ADDR_LEN
;
memcpy
(
dptr
,
skb
->
data
+
0
,
AX25_ADDR_LEN
);
memcpy
(
dptr
,
skb
->
data
+
0
,
AX25_ADDR_LEN
);
dptr
[
6
]
&=
~
AX25_CBIT
;
dptr
[
6
]
&=
~
AX25_CBIT
;
dptr
[
6
]
|=
AX25_EBIT
;
dptr
[
6
]
|=
AX25_EBIT
;
...
...
net/netrom/nr_timer.c
View file @
b331768e
/*
/*
* 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
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*
* Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org)
* 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.
*/
*/
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
...
@@ -144,33 +136,34 @@ static void nr_heartbeat_expiry(unsigned long param)
...
@@ -144,33 +136,34 @@ static void nr_heartbeat_expiry(unsigned long param)
struct
sock
*
sk
=
(
struct
sock
*
)
param
;
struct
sock
*
sk
=
(
struct
sock
*
)
param
;
nr_cb
*
nr
=
nr_sk
(
sk
);
nr_cb
*
nr
=
nr_sk
(
sk
);
bh_lock_sock
(
sk
);
switch
(
nr
->
state
)
{
switch
(
nr
->
state
)
{
case
NR_STATE_0
:
case
NR_STATE_0
:
/* Magic here: If we listen() and a new link dies before it
/* Magic here: If we listen() and a new link dies before it
is accepted() it isn't 'dead' so doesn't get removed. */
is accepted() it isn't 'dead' so doesn't get removed. */
if
(
sk
->
destroy
||
(
sk
->
state
==
TCP_LISTEN
&&
sk
->
dead
))
{
if
(
sk
->
destroy
||
(
sk
->
state
==
TCP_LISTEN
&&
sk
->
dead
))
{
nr_destroy_socket
(
sk
);
nr_destroy_socket
(
sk
);
return
;
return
;
}
}
break
;
break
;
case
NR_STATE_3
:
case
NR_STATE_3
:
/*
/*
* Check for the state of the receive buffer.
* Check for the state of the receive buffer.
*/
*/
if
(
atomic_read
(
&
sk
->
rmem_alloc
)
<
(
sk
->
rcvbuf
/
2
)
&&
if
(
atomic_read
(
&
sk
->
rmem_alloc
)
<
(
sk
->
rcvbuf
/
2
)
&&
(
nr
->
condition
&
NR_COND_OWN_RX_BUSY
))
{
(
nr
->
condition
&
NR_COND_OWN_RX_BUSY
))
{
nr
->
condition
&=
~
NR_COND_OWN_RX_BUSY
;
nr
->
condition
&=
~
NR_COND_OWN_RX_BUSY
;
nr
->
condition
&=
~
NR_COND_ACK_PENDING
;
nr
->
condition
&=
~
NR_COND_ACK_PENDING
;
nr
->
vl
=
nr
->
vr
;
nr
->
vl
=
nr
->
vr
;
nr_write_internal
(
sk
,
NR_INFOACK
);
nr_write_internal
(
sk
,
NR_INFOACK
);
break
;
}
break
;
break
;
}
break
;
}
}
nr_start_heartbeat
(
sk
);
nr_start_heartbeat
(
sk
);
bh_unlock_sock
(
sk
);
}
}
static
void
nr_t2timer_expiry
(
unsigned
long
param
)
static
void
nr_t2timer_expiry
(
unsigned
long
param
)
...
@@ -178,17 +171,21 @@ 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
;
struct
sock
*
sk
=
(
struct
sock
*
)
param
;
nr_cb
*
nr
=
nr_sk
(
sk
);
nr_cb
*
nr
=
nr_sk
(
sk
);
bh_lock_sock
(
sk
);
if
(
nr
->
condition
&
NR_COND_ACK_PENDING
)
{
if
(
nr
->
condition
&
NR_COND_ACK_PENDING
)
{
nr
->
condition
&=
~
NR_COND_ACK_PENDING
;
nr
->
condition
&=
~
NR_COND_ACK_PENDING
;
nr_enquiry_response
(
sk
);
nr_enquiry_response
(
sk
);
}
}
bh_unlock_sock
(
sk
);
}
}
static
void
nr_t4timer_expiry
(
unsigned
long
param
)
static
void
nr_t4timer_expiry
(
unsigned
long
param
)
{
{
struct
sock
*
sk
=
(
struct
sock
*
)
param
;
struct
sock
*
sk
=
(
struct
sock
*
)
param
;
bh_lock_sock
(
sk
);
nr_sk
(
sk
)
->
condition
&=
~
NR_COND_PEER_RX_BUSY
;
nr_sk
(
sk
)
->
condition
&=
~
NR_COND_PEER_RX_BUSY
;
bh_unlock_sock
(
sk
);
}
}
static
void
nr_idletimer_expiry
(
unsigned
long
param
)
static
void
nr_idletimer_expiry
(
unsigned
long
param
)
...
@@ -196,6 +193,8 @@ 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
;
struct
sock
*
sk
=
(
struct
sock
*
)
param
;
nr_cb
*
nr
=
nr_sk
(
sk
);
nr_cb
*
nr
=
nr_sk
(
sk
);
bh_lock_sock
(
sk
);
nr_clear_queues
(
sk
);
nr_clear_queues
(
sk
);
nr
->
n2count
=
0
;
nr
->
n2count
=
0
;
...
@@ -214,6 +213,7 @@ static void nr_idletimer_expiry(unsigned long param)
...
@@ -214,6 +213,7 @@ static void nr_idletimer_expiry(unsigned long param)
sk
->
state_change
(
sk
);
sk
->
state_change
(
sk
);
sk
->
dead
=
1
;
sk
->
dead
=
1
;
bh_unlock_sock
(
sk
);
}
}
static
void
nr_t1timer_expiry
(
unsigned
long
param
)
static
void
nr_t1timer_expiry
(
unsigned
long
param
)
...
@@ -221,38 +221,39 @@ static void nr_t1timer_expiry(unsigned long param)
...
@@ -221,38 +221,39 @@ static void nr_t1timer_expiry(unsigned long param)
struct
sock
*
sk
=
(
struct
sock
*
)
param
;
struct
sock
*
sk
=
(
struct
sock
*
)
param
;
nr_cb
*
nr
=
nr_sk
(
sk
);
nr_cb
*
nr
=
nr_sk
(
sk
);
bh_lock_sock
(
sk
);
switch
(
nr
->
state
)
{
switch
(
nr
->
state
)
{
case
NR_STATE_1
:
case
NR_STATE_1
:
if
(
nr
->
n2count
==
nr
->
n2
)
{
if
(
nr
->
n2count
==
nr
->
n2
)
{
nr_disconnect
(
sk
,
ETIMEDOUT
);
nr_disconnect
(
sk
,
ETIMEDOUT
);
return
;
return
;
}
else
{
}
else
{
nr
->
n2count
++
;
nr
->
n2count
++
;
nr_write_internal
(
sk
,
NR_CONNREQ
);
nr_write_internal
(
sk
,
NR_CONNREQ
);
}
}
break
;
break
;
case
NR_STATE_2
:
case
NR_STATE_2
:
if
(
nr
->
n2count
==
nr
->
n2
)
{
if
(
nr
->
n2count
==
nr
->
n2
)
{
nr_disconnect
(
sk
,
ETIMEDOUT
);
nr_disconnect
(
sk
,
ETIMEDOUT
);
return
;
return
;
}
else
{
}
else
{
nr
->
n2count
++
;
nr
->
n2count
++
;
nr_write_internal
(
sk
,
NR_DISCREQ
);
nr_write_internal
(
sk
,
NR_DISCREQ
);
}
}
break
;
break
;
case
NR_STATE_3
:
case
NR_STATE_3
:
if
(
nr
->
n2count
==
nr
->
n2
)
{
if
(
nr
->
n2count
==
nr
->
n2
)
{
nr_disconnect
(
sk
,
ETIMEDOUT
);
nr_disconnect
(
sk
,
ETIMEDOUT
);
return
;
return
;
}
else
{
}
else
{
nr
->
n2count
++
;
nr
->
n2count
++
;
nr_requeue_frames
(
sk
);
nr_requeue_frames
(
sk
);
}
}
break
;
break
;
}
}
nr_start_t1timer
(
sk
);
nr_start_t1timer
(
sk
);
bh_unlock_sock
(
sk
);
}
}
net/netrom/sysctl_net_netrom.c
View file @
b331768e
/* -*- 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.
* Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com)
* Added /proc/sys/net/netrom directory entry (empty =) ). [MS]
*/
*/
#include <linux/mm.h>
#include <linux/mm.h>
#include <linux/sysctl.h>
#include <linux/sysctl.h>
#include <linux/init.h>
#include <linux/init.h>
...
...
net/rose/af_rose.c
View file @
b331768e
/*
/*
* 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)
*
* Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* This module:
* Copyright (C) Terry Dawson VK2KTJ (terry@animats.net)
* This module is free software; you can redistribute it and/or
* Copyright (C) Tomi Manninen OH2BNS (oh2bns@sral.fi)
* 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
*/
*/
#include <linux/config.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/init.h>
...
@@ -33,6 +18,7 @@
...
@@ -33,6 +18,7 @@
#include <linux/in.h>
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/sockios.h>
...
@@ -47,7 +33,7 @@
...
@@ -47,7 +33,7 @@
#include <asm/system.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/uaccess.h>
#include <linux/fcntl.h>
#include <linux/fcntl.h>
#include <linux/termios.h>
/* For TIOCINQ/OUTQ */
#include <linux/termios.h>
#include <linux/mm.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/notifier.h>
#include <linux/notifier.h>
...
@@ -71,6 +57,7 @@ int sysctl_rose_maximum_vcs = ROSE_DEFAULT_MAXVC;
...
@@ -71,6 +57,7 @@ int sysctl_rose_maximum_vcs = ROSE_DEFAULT_MAXVC;
int
sysctl_rose_window_size
=
ROSE_DEFAULT_WINDOW_SIZE
;
int
sysctl_rose_window_size
=
ROSE_DEFAULT_WINDOW_SIZE
;
static
struct
sock
*
rose_list
;
static
struct
sock
*
rose_list
;
static
spinlock_t
rose_list_lock
=
SPIN_LOCK_UNLOCKED
;
static
struct
proto_ops
rose_proto_ops
;
static
struct
proto_ops
rose_proto_ops
;
...
@@ -173,27 +160,24 @@ decmod: MOD_DEC_USE_COUNT;
...
@@ -173,27 +160,24 @@ decmod: MOD_DEC_USE_COUNT;
static
void
rose_remove_socket
(
struct
sock
*
sk
)
static
void
rose_remove_socket
(
struct
sock
*
sk
)
{
{
struct
sock
*
s
;
struct
sock
*
s
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
rose_list_lock
);
if
((
s
=
rose_list
)
==
sk
)
{
if
((
s
=
rose_list
)
==
sk
)
{
rose_list
=
s
->
next
;
rose_list
=
s
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
rose_list_lock
);
return
;
return
;
}
}
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
if
(
s
->
next
==
sk
)
{
if
(
s
->
next
==
sk
)
{
s
->
next
=
sk
->
next
;
s
->
next
=
sk
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
rose_list_lock
);
return
;
return
;
}
}
s
=
s
->
next
;
s
=
s
->
next
;
}
}
spin_unlock_bh
(
&
rose_list_lock
);
restore_flags
(
flags
);
}
}
/*
/*
...
@@ -204,6 +188,7 @@ void rose_kill_by_neigh(struct rose_neigh *neigh)
...
@@ -204,6 +188,7 @@ void rose_kill_by_neigh(struct rose_neigh *neigh)
{
{
struct
sock
*
s
;
struct
sock
*
s
;
spin_lock_bh
(
&
rose_list_lock
);
for
(
s
=
rose_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
for
(
s
=
rose_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
rose_cb
*
rose
=
rose_sk
(
s
);
rose_cb
*
rose
=
rose_sk
(
s
);
...
@@ -213,6 +198,7 @@ void rose_kill_by_neigh(struct rose_neigh *neigh)
...
@@ -213,6 +198,7 @@ void rose_kill_by_neigh(struct rose_neigh *neigh)
rose
->
neighbour
=
NULL
;
rose
->
neighbour
=
NULL
;
}
}
}
}
spin_unlock_bh
(
&
rose_list_lock
);
}
}
/*
/*
...
@@ -221,7 +207,8 @@ void rose_kill_by_neigh(struct rose_neigh *neigh)
...
@@ -221,7 +207,8 @@ void rose_kill_by_neigh(struct rose_neigh *neigh)
static
void
rose_kill_by_device
(
struct
net_device
*
dev
)
static
void
rose_kill_by_device
(
struct
net_device
*
dev
)
{
{
struct
sock
*
s
;
struct
sock
*
s
;
spin_lock_bh
(
&
rose_list_lock
);
for
(
s
=
rose_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
for
(
s
=
rose_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
rose_cb
*
rose
=
rose_sk
(
s
);
rose_cb
*
rose
=
rose_sk
(
s
);
...
@@ -231,12 +218,14 @@ static void rose_kill_by_device(struct net_device *dev)
...
@@ -231,12 +218,14 @@ static void rose_kill_by_device(struct net_device *dev)
rose
->
device
=
NULL
;
rose
->
device
=
NULL
;
}
}
}
}
spin_unlock_bh
(
&
rose_list_lock
);
}
}
/*
/*
* Handle device status changes.
* 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
;
struct
net_device
*
dev
=
(
struct
net_device
*
)
ptr
;
...
@@ -244,13 +233,13 @@ static int rose_device_event(struct notifier_block *this, unsigned long event, v
...
@@ -244,13 +233,13 @@ static int rose_device_event(struct notifier_block *this, unsigned long event, v
return
NOTIFY_DONE
;
return
NOTIFY_DONE
;
switch
(
dev
->
type
)
{
switch
(
dev
->
type
)
{
case
ARPHRD_ROSE
:
case
ARPHRD_ROSE
:
rose_kill_by_device
(
dev
);
rose_kill_by_device
(
dev
);
break
;
break
;
case
ARPHRD_AX25
:
case
ARPHRD_AX25
:
rose_link_device_down
(
dev
);
rose_link_device_down
(
dev
);
rose_rt_device_down
(
dev
);
rose_rt_device_down
(
dev
);
break
;
break
;
}
}
return
NOTIFY_DONE
;
return
NOTIFY_DONE
;
...
@@ -261,14 +250,11 @@ static int rose_device_event(struct notifier_block *this, unsigned long event, v
...
@@ -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
)
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
;
sk
->
next
=
rose_list
;
rose_list
=
sk
;
rose_list
=
sk
;
spin_unlock_bh
(
&
rose_list_lock
);
restore_flags
(
flags
);
}
}
/*
/*
...
@@ -277,18 +263,16 @@ static void rose_insert_socket(struct sock *sk)
...
@@ -277,18 +263,16 @@ static void rose_insert_socket(struct sock *sk)
*/
*/
static
struct
sock
*
rose_find_listener
(
rose_address
*
addr
,
ax25_address
*
call
)
static
struct
sock
*
rose_find_listener
(
rose_address
*
addr
,
ax25_address
*
call
)
{
{
unsigned
long
flags
;
struct
sock
*
s
;
struct
sock
*
s
;
save_flags
(
flags
);
cli
();
spin_lock_bh
(
&
rose_list_lock
);
for
(
s
=
rose_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
for
(
s
=
rose_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
rose_cb
*
rose
=
rose_sk
(
s
);
rose_cb
*
rose
=
rose_sk
(
s
);
if
(
!
rosecmp
(
&
rose
->
source_addr
,
addr
)
&&
if
(
!
rosecmp
(
&
rose
->
source_addr
,
addr
)
&&
!
ax25cmp
(
&
rose
->
source_call
,
call
)
&&
!
ax25cmp
(
&
rose
->
source_call
,
call
)
&&
!
rose
->
source_ndigis
&&
s
->
state
==
TCP_LISTEN
)
{
!
rose
->
source_ndigis
&&
s
->
state
==
TCP_LISTEN
)
{
restore_flags
(
flags
);
spin_unlock_bh
(
&
rose_list_lock
);
return
s
;
return
s
;
}
}
}
}
...
@@ -299,12 +283,12 @@ static struct sock *rose_find_listener(rose_address *addr, ax25_address *call)
...
@@ -299,12 +283,12 @@ static struct sock *rose_find_listener(rose_address *addr, ax25_address *call)
if
(
!
rosecmp
(
&
rose
->
source_addr
,
addr
)
&&
if
(
!
rosecmp
(
&
rose
->
source_addr
,
addr
)
&&
!
ax25cmp
(
&
rose
->
source_call
,
&
null_ax25_address
)
&&
!
ax25cmp
(
&
rose
->
source_call
,
&
null_ax25_address
)
&&
s
->
state
==
TCP_LISTEN
)
{
s
->
state
==
TCP_LISTEN
)
{
restore_flags
(
flags
);
spin_unlock_bh
(
&
rose_list_lock
);
return
s
;
return
s
;
}
}
}
}
spin_unlock_bh
(
&
rose_list_lock
);
restore_flags
(
flags
);
return
NULL
;
return
NULL
;
}
}
...
@@ -314,20 +298,17 @@ static struct sock *rose_find_listener(rose_address *addr, ax25_address *call)
...
@@ -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
*
rose_find_socket
(
unsigned
int
lci
,
struct
rose_neigh
*
neigh
)
{
{
struct
sock
*
s
;
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
)
{
for
(
s
=
rose_list
;
s
!=
NULL
;
s
=
s
->
next
)
{
rose_cb
*
rose
=
rose_sk
(
s
);
rose_cb
*
rose
=
rose_sk
(
s
);
if
(
rose
->
lci
==
lci
&&
rose
->
neighbour
==
neigh
)
{
if
(
rose
->
lci
==
lci
&&
rose
->
neighbour
==
neigh
)
{
restore_flags
(
flags
);
spin_unlock_bh
(
&
rose_list_lock
);
return
s
;
return
s
;
}
}
}
}
spin_unlock_bh
(
&
rose_list_lock
);
restore_flags
(
flags
);
return
NULL
;
return
NULL
;
}
}
...
@@ -366,23 +347,20 @@ static void rose_destroy_timer(unsigned long data)
...
@@ -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
* This is called from user mode and the timers. Thus it protects itself
*
interrupt users but doesn't worry about being called during work.
*
against interrupt users but doesn't worry about being called during
*
Once it is removed from the queue no interrupt or bottom half will
*
work. Once it is removed from the queue no interrupt or bottom half
* touch it and we are (fairly 8-) ) safe.
*
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
;
struct
sk_buff
*
skb
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
rose_remove_socket
(
sk
);
rose_stop_heartbeat
(
sk
);
rose_stop_heartbeat
(
sk
);
rose_stop_idletimer
(
sk
);
rose_stop_idletimer
(
sk
);
rose_stop_timer
(
sk
);
rose_stop_timer
(
sk
);
rose_remove_socket
(
sk
);
rose_clear_queues
(
sk
);
/* Flush the queues */
rose_clear_queues
(
sk
);
/* Flush the queues */
while
((
skb
=
skb_dequeue
(
&
sk
->
receive_queue
))
!=
NULL
)
{
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
...
@@ -405,8 +383,6 @@ void rose_destroy_socket(struct sock *sk) /* Not static as it's used by the time
}
else
{
}
else
{
rose_free_sock
(
sk
);
rose_free_sock
(
sk
);
}
}
restore_flags
(
flags
);
}
}
/*
/*
...
@@ -431,46 +407,46 @@ static int rose_setsockopt(struct socket *sock, int level, int optname,
...
@@ -431,46 +407,46 @@ static int rose_setsockopt(struct socket *sock, int level, int optname,
return
-
EFAULT
;
return
-
EFAULT
;
switch
(
optname
)
{
switch
(
optname
)
{
case
ROSE_DEFER
:
case
ROSE_DEFER
:
rose
->
defer
=
opt
?
1
:
0
;
rose
->
defer
=
opt
?
1
:
0
;
return
0
;
return
0
;
case
ROSE_T1
:
case
ROSE_T1
:
if
(
opt
<
1
)
if
(
opt
<
1
)
return
-
EINVAL
;
return
-
EINVAL
;
rose
->
t1
=
opt
*
HZ
;
rose
->
t1
=
opt
*
HZ
;
return
0
;
return
0
;
case
ROSE_T2
:
case
ROSE_T2
:
if
(
opt
<
1
)
if
(
opt
<
1
)
return
-
EINVAL
;
return
-
EINVAL
;
rose
->
t2
=
opt
*
HZ
;
rose
->
t2
=
opt
*
HZ
;
return
0
;
return
0
;
case
ROSE_T3
:
case
ROSE_T3
:
if
(
opt
<
1
)
if
(
opt
<
1
)
return
-
EINVAL
;
return
-
EINVAL
;
rose
->
t3
=
opt
*
HZ
;
rose
->
t3
=
opt
*
HZ
;
return
0
;
return
0
;
case
ROSE_HOLDBACK
:
case
ROSE_HOLDBACK
:
if
(
opt
<
1
)
if
(
opt
<
1
)
return
-
EINVAL
;
return
-
EINVAL
;
rose
->
hb
=
opt
*
HZ
;
rose
->
hb
=
opt
*
HZ
;
return
0
;
return
0
;
case
ROSE_IDLE
:
case
ROSE_IDLE
:
if
(
opt
<
0
)
if
(
opt
<
0
)
return
-
EINVAL
;
return
-
EINVAL
;
rose
->
idle
=
opt
*
60
*
HZ
;
rose
->
idle
=
opt
*
60
*
HZ
;
return
0
;
return
0
;
case
ROSE_QBITINCL
:
case
ROSE_QBITINCL
:
rose
->
qbitincl
=
opt
?
1
:
0
;
rose
->
qbitincl
=
opt
?
1
:
0
;
return
0
;
return
0
;
default:
default:
return
-
ENOPROTOOPT
;
return
-
ENOPROTOOPT
;
}
}
}
}
...
@@ -484,44 +460,44 @@ static int rose_getsockopt(struct socket *sock, int level, int optname,
...
@@ -484,44 +460,44 @@ static int rose_getsockopt(struct socket *sock, int level, int optname,
if
(
level
!=
SOL_ROSE
)
if
(
level
!=
SOL_ROSE
)
return
-
ENOPROTOOPT
;
return
-
ENOPROTOOPT
;
if
(
get_user
(
len
,
optlen
))
if
(
get_user
(
len
,
optlen
))
return
-
EFAULT
;
return
-
EFAULT
;
if
(
len
<
0
)
if
(
len
<
0
)
return
-
EINVAL
;
return
-
EINVAL
;
switch
(
optname
)
{
switch
(
optname
)
{
case
ROSE_DEFER
:
case
ROSE_DEFER
:
val
=
rose
->
defer
;
val
=
rose
->
defer
;
break
;
break
;
case
ROSE_T1
:
case
ROSE_T1
:
val
=
rose
->
t1
/
HZ
;
val
=
rose
->
t1
/
HZ
;
break
;
break
;
case
ROSE_T2
:
case
ROSE_T2
:
val
=
rose
->
t2
/
HZ
;
val
=
rose
->
t2
/
HZ
;
break
;
break
;
case
ROSE_T3
:
case
ROSE_T3
:
val
=
rose
->
t3
/
HZ
;
val
=
rose
->
t3
/
HZ
;
break
;
break
;
case
ROSE_HOLDBACK
:
case
ROSE_HOLDBACK
:
val
=
rose
->
hb
/
HZ
;
val
=
rose
->
hb
/
HZ
;
break
;
break
;
case
ROSE_IDLE
:
case
ROSE_IDLE
:
val
=
rose
->
idle
/
(
60
*
HZ
);
val
=
rose
->
idle
/
(
60
*
HZ
);
break
;
break
;
case
ROSE_QBITINCL
:
case
ROSE_QBITINCL
:
val
=
rose
->
qbitincl
;
val
=
rose
->
qbitincl
;
break
;
break
;
default:
default:
return
-
ENOPROTOOPT
;
return
-
ENOPROTOOPT
;
}
}
len
=
min_t
(
unsigned
int
,
len
,
sizeof
(
int
));
len
=
min_t
(
unsigned
int
,
len
,
sizeof
(
int
));
...
@@ -565,7 +541,7 @@ static int rose_create(struct socket *sock, int protocol)
...
@@ -565,7 +541,7 @@ static int rose_create(struct socket *sock, int protocol)
rose
=
rose_sk
(
sk
);
rose
=
rose_sk
(
sk
);
sock_init_data
(
sock
,
sk
);
sock_init_data
(
sock
,
sk
);
skb_queue_head_init
(
&
rose
->
ack_queue
);
skb_queue_head_init
(
&
rose
->
ack_queue
);
#ifdef M_BIT
#ifdef M_BIT
skb_queue_head_init
(
&
rose
->
frag_queue
);
skb_queue_head_init
(
&
rose
->
frag_queue
);
...
@@ -647,39 +623,38 @@ static int rose_release(struct socket *sock)
...
@@ -647,39 +623,38 @@ static int rose_release(struct socket *sock)
rose
=
rose_sk
(
sk
);
rose
=
rose_sk
(
sk
);
switch
(
rose
->
state
)
{
switch
(
rose
->
state
)
{
case
ROSE_STATE_0
:
case
ROSE_STATE_0
:
rose_disconnect
(
sk
,
0
,
-
1
,
-
1
);
rose_disconnect
(
sk
,
0
,
-
1
,
-
1
);
rose_destroy_socket
(
sk
);
rose_destroy_socket
(
sk
);
break
;
break
;
case
ROSE_STATE_2
:
case
ROSE_STATE_2
:
rose
->
neighbour
->
use
--
;
rose
->
neighbour
->
use
--
;
rose_disconnect
(
sk
,
0
,
-
1
,
-
1
);
rose_disconnect
(
sk
,
0
,
-
1
,
-
1
);
rose_destroy_socket
(
sk
);
rose_destroy_socket
(
sk
);
break
;
break
;
case
ROSE_STATE_1
:
case
ROSE_STATE_1
:
case
ROSE_STATE_3
:
case
ROSE_STATE_3
:
case
ROSE_STATE_4
:
case
ROSE_STATE_4
:
case
ROSE_STATE_5
:
case
ROSE_STATE_5
:
rose_clear_queues
(
sk
);
rose_clear_queues
(
sk
);
rose_stop_idletimer
(
sk
);
rose_stop_idletimer
(
sk
);
rose_write_internal
(
sk
,
ROSE_CLEAR_REQUEST
);
rose_write_internal
(
sk
,
ROSE_CLEAR_REQUEST
);
rose_start_t3timer
(
sk
);
rose_start_t3timer
(
sk
);
rose
->
state
=
ROSE_STATE_2
;
rose
->
state
=
ROSE_STATE_2
;
sk
->
state
=
TCP_CLOSE
;
sk
->
state
=
TCP_CLOSE
;
sk
->
shutdown
|=
SEND_SHUTDOWN
;
sk
->
shutdown
|=
SEND_SHUTDOWN
;
sk
->
state_change
(
sk
);
sk
->
state_change
(
sk
);
sk
->
dead
=
1
;
sk
->
dead
=
1
;
sk
->
destroy
=
1
;
sk
->
destroy
=
1
;
break
;
break
;
default:
default:
break
;
break
;
}
}
sock
->
sk
=
NULL
;
sock
->
sk
=
NULL
;
sk
->
socket
=
NULL
;
/* Not used, but we should do this. **/
sk
->
socket
=
NULL
;
/* Not used, but we should do this. **/
return
0
;
return
0
;
...
@@ -842,71 +817,90 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
...
@@ -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
))
if
(
sk
->
state
!=
TCP_ESTABLISHED
&&
(
flags
&
O_NONBLOCK
))
return
-
EINPROGRESS
;
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
)
{
if
(
sk
->
state
==
TCP_SYN_SENT
)
{
interruptible_sleep_on
(
sk
->
sleep
);
struct
task_struct
*
tsk
=
current
;
if
(
signal_pending
(
current
))
{
DECLARE_WAITQUEUE
(
wait
,
tsk
);
sti
();
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
;
return
-
ERESTARTSYS
;
}
}
current
->
state
=
TASK_RUNNING
;
remove_wait_queue
(
sk
->
sleep
,
&
wait
);
}
}
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
{
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
{
sti
();
sock
->
state
=
SS_UNCONNECTED
;
sock
->
state
=
SS_UNCONNECTED
;
return
sock_error
(
sk
);
/* Always set at this point */
return
sock_error
(
sk
);
/* Always set at this point */
}
}
sock
->
state
=
SS_CONNECTED
;
sock
->
state
=
SS_CONNECTED
;
sti
();
return
0
;
return
0
;
}
}
static
int
rose_accept
(
struct
socket
*
sock
,
struct
socket
*
newsock
,
int
flags
)
static
int
rose_accept
(
struct
socket
*
sock
,
struct
socket
*
newsock
,
int
flags
)
{
{
struct
sock
*
sk
;
struct
task_struct
*
tsk
=
current
;
struct
sock
*
newsk
;
DECLARE_WAITQUEUE
(
wait
,
tsk
)
;
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
struct
sock
*
newsk
;
struct
sock
*
sk
;
int
err
=
0
;
if
((
sk
=
sock
->
sk
)
==
NULL
)
if
((
sk
=
sock
->
sk
)
==
NULL
)
return
-
EINVAL
;
return
-
EINVAL
;
if
(
sk
->
type
!=
SOCK_SEQPACKET
)
lock_sock
(
sk
);
return
-
EOPNOTSUPP
;
if
(
sk
->
type
!=
SOCK_SEQPACKET
)
{
err
=
-
EOPNOTSUPP
;
goto
out
;
}
if
(
sk
->
state
!=
TCP_LISTEN
)
if
(
sk
->
state
!=
TCP_LISTEN
)
{
return
-
EINVAL
;
err
=
-
EINVAL
;
goto
out
;
}
/*
/*
* The write queue this time is holding sockets ready to use
* The write queue this time is holding sockets ready to use
* hooked into the SABM we saved
* hooked into the SABM we saved
*/
*/
do
{
add_wait_queue
(
sk
->
sleep
,
&
wait
);
cli
();
for
(;;)
{
if
((
skb
=
skb_dequeue
(
&
sk
->
receive_queue
))
==
NULL
)
{
skb
=
skb_dequeue
(
&
sk
->
receive_queue
);
if
(
flags
&
O_NONBLOCK
)
{
if
(
skb
)
sti
();
break
;
return
-
EWOULDBLOCK
;
}
current
->
state
=
TASK_INTERRUPTIBLE
;
interruptible_sleep_on
(
sk
->
sleep
);
release_sock
(
sk
);
if
(
signal_pending
(
current
))
{
if
(
flags
&
O_NONBLOCK
)
sti
();
return
-
EWOULDBLOCK
;
return
-
ERESTARTSYS
;
if
(
!
signal_pending
(
tsk
))
{
}
schedule
();
lock_sock
(
sk
);
continue
;
}
}
}
while
(
skb
==
NULL
);
return
-
ERESTARTSYS
;
}
current
->
state
=
TASK_RUNNING
;
remove_wait_queue
(
sk
->
sleep
,
&
wait
);
newsk
=
skb
->
sk
;
newsk
=
skb
->
sk
;
newsk
->
pair
=
NULL
;
newsk
->
pair
=
NULL
;
newsk
->
socket
=
newsock
;
newsk
->
socket
=
newsock
;
newsk
->
sleep
=
&
newsock
->
wait
;
newsk
->
sleep
=
&
newsock
->
wait
;
sti
();
/* Now attach up the new socket */
/* Now attach up the new socket */
skb
->
sk
=
NULL
;
skb
->
sk
=
NULL
;
...
@@ -914,7 +908,10 @@ static int rose_accept(struct socket *sock, struct socket *newsock, int flags)
...
@@ -914,7 +908,10 @@ static int rose_accept(struct socket *sock, struct socket *newsock, int flags)
sk
->
ack_backlog
--
;
sk
->
ack_backlog
--
;
newsock
->
sk
=
newsk
;
newsock
->
sk
=
newsk
;
return
0
;
out:
release_sock
(
sk
);
return
err
;
}
}
static
int
rose_getname
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
static
int
rose_getname
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
...
@@ -961,7 +958,7 @@ int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct ros
...
@@ -961,7 +958,7 @@ int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct ros
* skb->data points to the rose frame start
* skb->data points to the rose frame start
*/
*/
memset
(
&
facilities
,
0x00
,
sizeof
(
struct
rose_facilities_struct
));
memset
(
&
facilities
,
0x00
,
sizeof
(
struct
rose_facilities_struct
));
len
=
(((
skb
->
data
[
3
]
>>
4
)
&
0x0F
)
+
1
)
/
2
;
len
=
(((
skb
->
data
[
3
]
>>
4
)
&
0x0F
)
+
1
)
/
2
;
len
+=
(((
skb
->
data
[
3
]
>>
0
)
&
0x0F
)
+
1
)
/
2
;
len
+=
(((
skb
->
data
[
3
]
>>
0
)
&
0x0F
)
+
1
)
/
2
;
if
(
!
rose_parse_facilities
(
skb
->
data
+
len
+
4
,
&
facilities
))
{
if
(
!
rose_parse_facilities
(
skb
->
data
+
len
+
4
,
&
facilities
))
{
...
@@ -1028,7 +1025,7 @@ int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct ros
...
@@ -1028,7 +1025,7 @@ int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct ros
return
1
;
return
1
;
}
}
static
int
rose_sendmsg
(
struct
socket
*
sock
,
struct
msghdr
*
msg
,
int
len
,
static
int
rose_sendmsg
(
struct
socket
*
sock
,
struct
msghdr
*
msg
,
int
len
,
struct
scm_cookie
*
scm
)
struct
scm_cookie
*
scm
)
{
{
struct
sock
*
sk
=
sock
->
sk
;
struct
sock
*
sk
=
sock
->
sk
;
...
@@ -1131,7 +1128,7 @@ static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len,
...
@@ -1131,7 +1128,7 @@ static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len,
SOCK_DEBUG
(
sk
,
"ROSE: Built header.
\n
"
);
SOCK_DEBUG
(
sk
,
"ROSE: Built header.
\n
"
);
SOCK_DEBUG
(
sk
,
"ROSE: Transmitting buffer
\n
"
);
SOCK_DEBUG
(
sk
,
"ROSE: Transmitting buffer
\n
"
);
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
{
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
{
kfree_skb
(
skb
);
kfree_skb
(
skb
);
return
-
ENOTCONN
;
return
-
ENOTCONN
;
...
@@ -1144,7 +1141,7 @@ static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len,
...
@@ -1144,7 +1141,7 @@ static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len,
struct
sk_buff
*
skbn
;
struct
sk_buff
*
skbn
;
int
frontlen
;
int
frontlen
;
int
lg
;
int
lg
;
/* Save a copy of the Header */
/* Save a copy of the Header */
memcpy
(
header
,
skb
->
data
,
ROSE_MIN_LEN
);
memcpy
(
header
,
skb
->
data
,
ROSE_MIN_LEN
);
skb_pull
(
skb
,
ROSE_MIN_LEN
);
skb_pull
(
skb
,
ROSE_MIN_LEN
);
...
@@ -1173,10 +1170,10 @@ static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len,
...
@@ -1173,10 +1170,10 @@ static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len,
if
(
skb
->
len
>
0
)
if
(
skb
->
len
>
0
)
skbn
->
data
[
2
]
|=
M_BIT
;
skbn
->
data
[
2
]
|=
M_BIT
;
skb_queue_tail
(
&
sk
->
write_queue
,
skbn
);
/* Throw it on the queue */
skb_queue_tail
(
&
sk
->
write_queue
,
skbn
);
/* Throw it on the queue */
}
}
skb
->
free
=
1
;
skb
->
free
=
1
;
kfree_skb
(
skb
,
FREE_WRITE
);
kfree_skb
(
skb
,
FREE_WRITE
);
}
else
{
}
else
{
...
@@ -1192,7 +1189,7 @@ static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len,
...
@@ -1192,7 +1189,7 @@ static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len,
}
}
static
int
rose_recvmsg
(
struct
socket
*
sock
,
struct
msghdr
*
msg
,
int
size
,
static
int
rose_recvmsg
(
struct
socket
*
sock
,
struct
msghdr
*
msg
,
int
size
,
int
flags
,
struct
scm_cookie
*
scm
)
int
flags
,
struct
scm_cookie
*
scm
)
{
{
struct
sock
*
sk
=
sock
->
sk
;
struct
sock
*
sk
=
sock
->
sk
;
...
@@ -1264,96 +1261,96 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
...
@@ -1264,96 +1261,96 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
rose_cb
*
rose
=
rose_sk
(
sk
);
rose_cb
*
rose
=
rose_sk
(
sk
);
switch
(
cmd
)
{
switch
(
cmd
)
{
case
TIOCOUTQ
:
{
case
TIOCOUTQ
:
{
long
amount
;
long
amount
;
amount
=
sk
->
sndbuf
-
atomic_read
(
&
sk
->
wmem_alloc
);
amount
=
sk
->
sndbuf
-
atomic_read
(
&
sk
->
wmem_alloc
);
if
(
amount
<
0
)
if
(
amount
<
0
)
amount
=
0
;
amount
=
0
;
return
put_user
(
amount
,
(
unsigned
int
*
)
arg
);
return
put_user
(
amount
,
(
unsigned
int
*
)
arg
);
}
}
case
TIOCINQ
:
{
case
TIOCINQ
:
{
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
long
amount
=
0L
;
long
amount
=
0L
;
/* These two are safe on a single CPU system as only user tasks fiddle here */
/* These two are safe on a single CPU system as only user tasks fiddle here */
if
((
skb
=
skb_peek
(
&
sk
->
receive_queue
))
!=
NULL
)
if
((
skb
=
skb_peek
(
&
sk
->
receive_queue
))
!=
NULL
)
amount
=
skb
->
len
;
amount
=
skb
->
len
;
return
put_user
(
amount
,
(
unsigned
int
*
)
arg
);
return
put_user
(
amount
,
(
unsigned
int
*
)
arg
);
}
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
;
}
}
return
-
EINVAL
;
case
SIOCGSTAMP
:
case
SIOCGIFADDR
:
if
(
sk
!=
NULL
)
{
case
SIOCSIFADDR
:
if
(
sk
->
stamp
.
tv_sec
==
0
)
case
SIOCGIFDSTADDR
:
return
-
ENOENT
;
case
SIOCSIFDSTADDR
:
return
copy_to_user
((
void
*
)
arg
,
&
sk
->
stamp
,
sizeof
(
struct
timeval
))
?
-
EFAULT
:
0
;
case
SIOCGIFBRDADDR
:
}
case
SIOCSIFBRDADDR
:
return
-
EINVAL
;
case
SIOCGIFNETMASK
:
case
SIOCSIFNETMASK
:
case
SIOCGIFMETRIC
:
case
SIOCSIFMETRIC
:
return
-
EINVAL
;
case
SIOCGIFADDR
:
case
SIOCADDRT
:
case
SIOCSIFADDR
:
case
SIOCDELRT
:
case
SIOCGIFDSTADDR
:
case
SIOCRSCLRRT
:
case
SIOCSIFDSTADDR
:
if
(
!
capable
(
CAP_NET_ADMIN
))
case
SIOCGIFBRDADDR
:
return
-
EPERM
;
case
SIOCSIFBRDADDR
:
return
rose_rt_ioctl
(
cmd
,
(
void
*
)
arg
);
case
SIOCGIFNETMASK
:
case
SIOCSIFNETMASK
:
case
SIOCRSGCAUSE
:
{
case
SIOCGIFMETRIC
:
struct
rose_cause_struct
rose_cause
;
case
SIOCSIFMETRIC
:
rose_cause
.
cause
=
rose
->
cause
;
return
-
EINVAL
;
rose_cause
.
diagnostic
=
rose
->
diagnostic
;
return
copy_to_user
((
void
*
)
arg
,
&
rose_cause
,
sizeof
(
struct
rose_cause_struct
))
?
-
EFAULT
:
0
;
}
case
SIOCADDRT
:
case
SIOCRSSCAUSE
:
{
case
SIOCDELRT
:
struct
rose_cause_struct
rose_cause
;
case
SIOCRSCLRRT
:
if
(
copy_from_user
(
&
rose_cause
,
(
void
*
)
arg
,
sizeof
(
struct
rose_cause_struct
)))
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
return
-
EFAULT
;
return
rose_rt_ioctl
(
cmd
,
(
void
*
)
arg
);
rose
->
cause
=
rose_cause
.
cause
;
rose
->
diagnostic
=
rose_cause
.
diagnostic
;
case
SIOCRSGCAUSE
:
{
return
0
;
struct
rose_cause_struct
rose_cause
;
}
rose_cause
.
cause
=
rose
->
cause
;
rose_cause
.
diagnostic
=
rose
->
diagnostic
;
return
copy_to_user
((
void
*
)
arg
,
&
rose_cause
,
sizeof
(
struct
rose_cause_struct
))
?
-
EFAULT
:
0
;
}
case
SIOCRSSCAUSE
:
{
case
SIOCRSSL2CALL
:
struct
rose_cause_struct
rose_cause
;
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
if
(
copy_from_user
(
&
rose_cause
,
(
void
*
)
arg
,
sizeof
(
struct
rose_cause_struct
)))
if
(
ax25cmp
(
&
rose_callsign
,
&
null_ax25_address
)
!=
0
)
return
-
EFAULT
;
ax25_listen_release
(
&
rose_callsign
,
NULL
);
rose
->
cause
=
rose_cause
.
cause
;
if
(
copy_from_user
(
&
rose_callsign
,
(
void
*
)
arg
,
sizeof
(
ax25_address
)))
rose
->
diagnostic
=
rose_cause
.
diagnostic
;
return
-
EFAULT
;
return
0
;
if
(
ax25cmp
(
&
rose_callsign
,
&
null_ax25_address
)
!=
0
)
}
ax25_listen_register
(
&
rose_callsign
,
NULL
);
return
0
;
case
SIOCRSSL2CALL
:
case
SIOCRSGL2CALL
:
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
return
copy_to_user
((
void
*
)
arg
,
&
rose_callsign
,
sizeof
(
ax25_address
))
?
-
EFAULT
:
0
;
if
(
ax25cmp
(
&
rose_callsign
,
&
null_ax25_address
)
!=
0
)
ax25_listen_release
(
&
rose_callsign
,
NULL
);
case
SIOCRSACCEPT
:
if
(
copy_from_user
(
&
rose_callsign
,
(
void
*
)
arg
,
sizeof
(
ax25_address
)))
if
(
rose
->
state
==
ROSE_STATE_5
)
{
return
-
EFAULT
;
rose_write_internal
(
sk
,
ROSE_CALL_ACCEPTED
);
if
(
ax25cmp
(
&
rose_callsign
,
&
null_ax25_address
)
!=
0
)
rose_start_idletimer
(
sk
);
ax25_listen_register
(
&
rose_callsign
,
NULL
);
rose
->
condition
=
0x00
;
return
0
;
rose
->
vs
=
0
;
rose
->
va
=
0
;
case
SIOCRSGL2CALL
:
rose
->
vr
=
0
;
return
copy_to_user
((
void
*
)
arg
,
&
rose_callsign
,
sizeof
(
ax25_address
))
?
-
EFAULT
:
0
;
rose
->
vl
=
0
;
rose
->
state
=
ROSE_STATE_3
;
case
SIOCRSACCEPT
:
}
if
(
rose
->
state
==
ROSE_STATE_5
)
{
return
0
;
rose_write_internal
(
sk
,
ROSE_CALL_ACCEPTED
);
rose_start_idletimer
(
sk
);
rose
->
condition
=
0x00
;
rose
->
vs
=
0
;
rose
->
va
=
0
;
rose
->
vr
=
0
;
rose
->
vl
=
0
;
rose
->
state
=
ROSE_STATE_3
;
}
return
0
;
default:
default:
return
dev_ioctl
(
cmd
,
(
void
*
)
arg
);
return
dev_ioctl
(
cmd
,
(
void
*
)
arg
);
}
}
/*NOTREACHED*/
return
0
;
return
0
;
}
}
...
@@ -1366,7 +1363,7 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -1366,7 +1363,7 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length)
off_t
pos
=
0
;
off_t
pos
=
0
;
off_t
begin
=
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
"
);
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
"
);
...
@@ -1390,7 +1387,7 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -1390,7 +1387,7 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length)
len
+=
sprintf
(
buffer
+
len
,
"%-10s %-9s %-5s %3.3X %05d %d %d %d %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld
\n
"
,
len
+=
sprintf
(
buffer
+
len
,
"%-10s %-9s %-5s %3.3X %05d %d %d %d %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld
\n
"
,
rose2asc
(
&
rose
->
source_addr
),
rose2asc
(
&
rose
->
source_addr
),
callsign
,
callsign
,
devname
,
devname
,
rose
->
lci
&
0x0FFF
,
rose
->
lci
&
0x0FFF
,
(
rose
->
neighbour
)
?
rose
->
neighbour
->
number
:
0
,
(
rose
->
neighbour
)
?
rose
->
neighbour
->
number
:
0
,
rose
->
state
,
rose
->
state
,
...
@@ -1418,48 +1415,44 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -1418,48 +1415,44 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length)
if
(
pos
>
offset
+
length
)
if
(
pos
>
offset
+
length
)
break
;
break
;
}
}
spin_unlock_bh
(
&
rose_list_lock
);
sti
();
*
start
=
buffer
+
(
offset
-
begin
);
*
start
=
buffer
+
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
if
(
len
>
length
)
len
=
length
;
if
(
len
>
length
)
len
=
length
;
return
(
len
)
;
return
len
;
}
}
static
struct
net_proto_family
rose_family_ops
=
{
static
struct
net_proto_family
rose_family_ops
=
{
.
family
=
PF_ROSE
,
.
family
=
PF_ROSE
,
.
create
=
rose_create
,
.
create
=
rose_create
,
};
};
static
struct
proto_ops
SOCKOPS_WRAPPED
(
rose_proto_ops
)
=
{
static
struct
proto_ops
rose_proto_ops
=
{
.
family
=
PF_ROSE
,
.
family
=
PF_ROSE
,
.
release
=
rose_release
,
.
release
=
rose_release
,
.
bind
=
rose_bind
,
.
bind
=
rose_bind
,
.
connect
=
rose_connect
,
.
connect
=
rose_connect
,
.
socketpair
=
sock_no_socketpair
,
.
socketpair
=
sock_no_socketpair
,
.
accept
=
rose_accept
,
.
accept
=
rose_accept
,
.
getname
=
rose_getname
,
.
getname
=
rose_getname
,
.
poll
=
datagram_poll
,
.
poll
=
datagram_poll
,
.
ioctl
=
rose_ioctl
,
.
ioctl
=
rose_ioctl
,
.
listen
=
rose_listen
,
.
listen
=
rose_listen
,
.
shutdown
=
sock_no_shutdown
,
.
shutdown
=
sock_no_shutdown
,
.
setsockopt
=
rose_setsockopt
,
.
setsockopt
=
rose_setsockopt
,
.
getsockopt
=
rose_getsockopt
,
.
getsockopt
=
rose_getsockopt
,
.
sendmsg
=
rose_sendmsg
,
.
sendmsg
=
rose_sendmsg
,
.
recvmsg
=
rose_recvmsg
,
.
recvmsg
=
rose_recvmsg
,
.
mmap
=
sock_no_mmap
,
.
mmap
=
sock_no_mmap
,
.
sendpage
=
sock_no_sendpage
,
.
sendpage
=
sock_no_sendpage
,
};
};
#include <linux/smp_lock.h>
SOCKOPS_WRAP
(
rose_proto
,
PF_ROSE
);
static
struct
notifier_block
rose_dev_notifier
=
{
static
struct
notifier_block
rose_dev_notifier
=
{
.
notifier_call
=
rose_device_event
,
.
notifier_call
=
rose_device_event
,
};
};
static
struct
net_device
*
dev_rose
;
static
struct
net_device
*
dev_rose
;
...
@@ -1555,5 +1548,5 @@ static void __exit rose_exit(void)
...
@@ -1555,5 +1548,5 @@ static void __exit rose_exit(void)
kfree
(
dev_rose
);
kfree
(
dev_rose
);
}
}
module_exit
(
rose_exit
);
module_exit
(
rose_exit
);
net/rose/rose_dev.c
View file @
b331768e
/*
/*
* 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.
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from nr_dev.c.
* Hans(PE1AYX) Fixed interface to IP layer.
*/
*/
#include <linux/config.h>
#include <linux/config.h>
#define __NO_VERSION__
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/module.h>
...
@@ -29,7 +21,7 @@
...
@@ -29,7 +21,7 @@
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/fcntl.h>
#include <linux/in.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/system.h>
#include <asm/io.h>
#include <asm/io.h>
...
...
net/rose/rose_in.c
View file @
b331768e
/*
/*
* 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:
* Most of this code is based on the SDL diagrams published in the 7th ARRL
* This module is free software; you can redistribute it and/or
* Computer Networking Conference papers. The diagrams have mistakes in them,
* modify it under the terms of the GNU General Public License
* but are mostly correct. Before you modify the code could you read the SDL
* as published by the Free Software Foundation; either version
* diagrams as the code is not obvious and probably very easy to break.
* 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.
*/
*/
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
...
@@ -55,29 +44,28 @@ static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int framety
...
@@ -55,29 +44,28 @@ static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int framety
rose_cb
*
rose
=
rose_sk
(
sk
);
rose_cb
*
rose
=
rose_sk
(
sk
);
switch
(
frametype
)
{
switch
(
frametype
)
{
case
ROSE_CALL_ACCEPTED
:
rose_stop_timer
(
sk
);
rose_start_idletimer
(
sk
);
rose
->
condition
=
0x00
;
rose
->
vs
=
0
;
rose
->
va
=
0
;
rose
->
vr
=
0
;
rose
->
vl
=
0
;
rose
->
state
=
ROSE_STATE_3
;
sk
->
state
=
TCP_ESTABLISHED
;
if
(
!
sk
->
dead
)
sk
->
state_change
(
sk
);
break
;
case
ROSE_CLEAR_REQUEST
:
rose_write_internal
(
sk
,
ROSE_CLEAR_CONFIRMATION
);
rose_disconnect
(
sk
,
ECONNREFUSED
,
skb
->
data
[
3
],
skb
->
data
[
4
]);
rose
->
neighbour
->
use
--
;
break
;
case
ROSE_CALL_ACCEPTED
:
default:
rose_stop_timer
(
sk
);
break
;
rose_start_idletimer
(
sk
);
rose
->
condition
=
0x00
;
rose
->
vs
=
0
;
rose
->
va
=
0
;
rose
->
vr
=
0
;
rose
->
vl
=
0
;
rose
->
state
=
ROSE_STATE_3
;
sk
->
state
=
TCP_ESTABLISHED
;
if
(
!
sk
->
dead
)
sk
->
state_change
(
sk
);
break
;
case
ROSE_CLEAR_REQUEST
:
rose_write_internal
(
sk
,
ROSE_CLEAR_CONFIRMATION
);
rose_disconnect
(
sk
,
ECONNREFUSED
,
skb
->
data
[
3
],
skb
->
data
[
4
]);
rose
->
neighbour
->
use
--
;
break
;
default:
break
;
}
}
return
0
;
return
0
;
...
@@ -93,20 +81,19 @@ static int rose_state2_machine(struct sock *sk, struct sk_buff *skb, int framety
...
@@ -93,20 +81,19 @@ static int rose_state2_machine(struct sock *sk, struct sk_buff *skb, int framety
rose_cb
*
rose
=
rose_sk
(
sk
);
rose_cb
*
rose
=
rose_sk
(
sk
);
switch
(
frametype
)
{
switch
(
frametype
)
{
case
ROSE_CLEAR_REQUEST
:
rose_write_internal
(
sk
,
ROSE_CLEAR_CONFIRMATION
);
rose_disconnect
(
sk
,
0
,
skb
->
data
[
3
],
skb
->
data
[
4
]);
rose
->
neighbour
->
use
--
;
break
;
case
ROSE_CLEAR_REQUEST
:
case
ROSE_CLEAR_CONFIRMATION
:
rose_write_internal
(
sk
,
ROSE_CLEAR_CONFIRMATION
);
rose_disconnect
(
sk
,
0
,
-
1
,
-
1
);
rose_disconnect
(
sk
,
0
,
skb
->
data
[
3
],
skb
->
data
[
4
]);
rose
->
neighbour
->
use
--
;
rose
->
neighbour
->
use
--
;
break
;
break
;
case
ROSE_CLEAR_CONFIRMATION
:
rose_disconnect
(
sk
,
0
,
-
1
,
-
1
);
rose
->
neighbour
->
use
--
;
break
;
default:
default:
break
;
break
;
}
}
return
0
;
return
0
;
...
@@ -123,50 +110,68 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
...
@@ -123,50 +110,68 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
int
queued
=
0
;
int
queued
=
0
;
switch
(
frametype
)
{
switch
(
frametype
)
{
case
ROSE_RESET_REQUEST
:
rose_stop_timer
(
sk
);
rose_start_idletimer
(
sk
);
rose_write_internal
(
sk
,
ROSE_RESET_CONFIRMATION
);
rose
->
condition
=
0x00
;
rose
->
vs
=
0
;
rose
->
vr
=
0
;
rose
->
va
=
0
;
rose
->
vl
=
0
;
rose_requeue_frames
(
sk
);
break
;
case
ROSE_CLEAR_REQUEST
:
rose_write_internal
(
sk
,
ROSE_CLEAR_CONFIRMATION
);
rose_disconnect
(
sk
,
0
,
skb
->
data
[
3
],
skb
->
data
[
4
]);
rose
->
neighbour
->
use
--
;
break
;
case
ROSE_RESET_REQUEST
:
case
ROSE_RR
:
rose_stop_timer
(
sk
);
case
ROSE_RNR
:
rose_start_idletimer
(
sk
);
if
(
!
rose_validate_nr
(
sk
,
nr
))
{
rose_write_internal
(
sk
,
ROSE_RESET_
CONFIRMATION
);
rose_write_internal
(
sk
,
ROSE_RESET_
REQUEST
);
rose
->
condition
=
0x00
;
rose
->
condition
=
0x00
;
rose
->
vs
=
0
;
rose
->
vs
=
0
;
rose
->
vr
=
0
;
rose
->
vr
=
0
;
rose
->
va
=
0
;
rose
->
va
=
0
;
rose
->
vl
=
0
;
rose
->
vl
=
0
;
rose_requeue_frames
(
sk
);
rose
->
state
=
ROSE_STATE_4
;
break
;
rose_start_t2timer
(
sk
);
rose_stop_idletimer
(
sk
);
case
ROSE_CLEAR_REQUEST
:
}
else
{
rose_write_internal
(
sk
,
ROSE_CLEAR_CONFIRMATION
);
rose_frames_acked
(
sk
,
nr
);
rose_disconnect
(
sk
,
0
,
skb
->
data
[
3
],
skb
->
data
[
4
]);
if
(
frametype
==
ROSE_RNR
)
{
rose
->
neighbour
->
use
--
;
rose
->
condition
|=
ROSE_COND_PEER_RX_BUSY
;
break
;
case
ROSE_RR
:
case
ROSE_RNR
:
if
(
!
rose_validate_nr
(
sk
,
nr
))
{
rose_write_internal
(
sk
,
ROSE_RESET_REQUEST
);
rose
->
condition
=
0x00
;
rose
->
vs
=
0
;
rose
->
vr
=
0
;
rose
->
va
=
0
;
rose
->
vl
=
0
;
rose
->
state
=
ROSE_STATE_4
;
rose_start_t2timer
(
sk
);
rose_stop_idletimer
(
sk
);
}
else
{
}
else
{
rose_frames_acked
(
sk
,
nr
);
rose
->
condition
&=
~
ROSE_COND_PEER_RX_BUSY
;
if
(
frametype
==
ROSE_RNR
)
{
rose
->
condition
|=
ROSE_COND_PEER_RX_BUSY
;
}
else
{
rose
->
condition
&=
~
ROSE_COND_PEER_RX_BUSY
;
}
}
}
break
;
}
break
;
case
ROSE_DATA
:
/* XXX */
case
ROSE_DATA
:
/* XXX */
rose
->
condition
&=
~
ROSE_COND_PEER_RX_BUSY
;
rose
->
condition
&=
~
ROSE_COND_PEER_RX_BUSY
;
if
(
!
rose_validate_nr
(
sk
,
nr
))
{
if
(
!
rose_validate_nr
(
sk
,
nr
))
{
rose_write_internal
(
sk
,
ROSE_RESET_REQUEST
);
rose
->
condition
=
0x00
;
rose
->
vs
=
0
;
rose
->
vr
=
0
;
rose
->
va
=
0
;
rose
->
vl
=
0
;
rose
->
state
=
ROSE_STATE_4
;
rose_start_t2timer
(
sk
);
rose_stop_idletimer
(
sk
);
break
;
}
rose_frames_acked
(
sk
,
nr
);
if
(
ns
==
rose
->
vr
)
{
rose_start_idletimer
(
sk
);
if
(
sock_queue_rcv_skb
(
sk
,
skb
)
==
0
)
{
rose
->
vr
=
(
rose
->
vr
+
1
)
%
ROSE_MODULUS
;
queued
=
1
;
}
else
{
/* Should never happen ! */
rose_write_internal
(
sk
,
ROSE_RESET_REQUEST
);
rose_write_internal
(
sk
,
ROSE_RESET_REQUEST
);
rose
->
condition
=
0x00
;
rose
->
condition
=
0x00
;
rose
->
vs
=
0
;
rose
->
vs
=
0
;
...
@@ -178,45 +183,26 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
...
@@ -178,45 +183,26 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
rose_stop_idletimer
(
sk
);
rose_stop_idletimer
(
sk
);
break
;
break
;
}
}
rose_frames_acked
(
sk
,
nr
);
if
(
atomic_read
(
&
sk
->
rmem_alloc
)
>
(
sk
->
rcvbuf
/
2
))
if
(
ns
==
rose
->
vr
)
{
rose
->
condition
|=
ROSE_COND_OWN_RX_BUSY
;
rose_start_idletimer
(
sk
);
}
if
(
sock_queue_rcv_skb
(
sk
,
skb
)
==
0
)
{
/*
rose
->
vr
=
(
rose
->
vr
+
1
)
%
ROSE_MODULUS
;
* If the window is full, ack the frame, else start the
queued
=
1
;
* acknowledge hold back timer.
}
else
{
*/
/* Should never happen ! */
if
(((
rose
->
vl
+
sysctl_rose_window_size
)
%
ROSE_MODULUS
)
==
rose
->
vr
)
{
rose_write_internal
(
sk
,
ROSE_RESET_REQUEST
);
rose
->
condition
&=
~
ROSE_COND_ACK_PENDING
;
rose
->
condition
=
0x00
;
rose_stop_timer
(
sk
);
rose
->
vs
=
0
;
rose_enquiry_response
(
sk
);
rose
->
vr
=
0
;
}
else
{
rose
->
va
=
0
;
rose
->
condition
|=
ROSE_COND_ACK_PENDING
;
rose
->
vl
=
0
;
rose_start_hbtimer
(
sk
);
rose
->
state
=
ROSE_STATE_4
;
}
rose_start_t2timer
(
sk
);
break
;
rose_stop_idletimer
(
sk
);
break
;
default:
}
printk
(
KERN_WARNING
"ROSE: unknown %02X in state 3
\n
"
,
frametype
);
if
(
atomic_read
(
&
sk
->
rmem_alloc
)
>
(
sk
->
rcvbuf
/
2
))
break
;
rose
->
condition
|=
ROSE_COND_OWN_RX_BUSY
;
}
/*
* If the window is full, ack the frame, else start the
* acknowledge hold back timer.
*/
if
(((
rose
->
vl
+
sysctl_rose_window_size
)
%
ROSE_MODULUS
)
==
rose
->
vr
)
{
rose
->
condition
&=
~
ROSE_COND_ACK_PENDING
;
rose_stop_timer
(
sk
);
rose_enquiry_response
(
sk
);
}
else
{
rose
->
condition
|=
ROSE_COND_ACK_PENDING
;
rose_start_hbtimer
(
sk
);
}
break
;
default:
printk
(
KERN_WARNING
"ROSE: unknown %02X in state 3
\n
"
,
frametype
);
break
;
}
}
return
queued
;
return
queued
;
...
@@ -232,29 +218,28 @@ static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int framety
...
@@ -232,29 +218,28 @@ static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int framety
rose_cb
*
rose
=
rose_sk
(
sk
);
rose_cb
*
rose
=
rose_sk
(
sk
);
switch
(
frametype
)
{
switch
(
frametype
)
{
case
ROSE_RESET_REQUEST
:
rose_write_internal
(
sk
,
ROSE_RESET_CONFIRMATION
);
case
ROSE_RESET_CONFIRMATION
:
rose_stop_timer
(
sk
);
rose_start_idletimer
(
sk
);
rose
->
condition
=
0x00
;
rose
->
va
=
0
;
rose
->
vr
=
0
;
rose
->
vs
=
0
;
rose
->
vl
=
0
;
rose
->
state
=
ROSE_STATE_3
;
rose_requeue_frames
(
sk
);
break
;
case
ROSE_CLEAR_REQUEST
:
rose_write_internal
(
sk
,
ROSE_CLEAR_CONFIRMATION
);
rose_disconnect
(
sk
,
0
,
skb
->
data
[
3
],
skb
->
data
[
4
]);
rose
->
neighbour
->
use
--
;
break
;
case
ROSE_RESET_REQUEST
:
default:
rose_write_internal
(
sk
,
ROSE_RESET_CONFIRMATION
);
break
;
case
ROSE_RESET_CONFIRMATION
:
rose_stop_timer
(
sk
);
rose_start_idletimer
(
sk
);
rose
->
condition
=
0x00
;
rose
->
va
=
0
;
rose
->
vr
=
0
;
rose
->
vs
=
0
;
rose
->
vl
=
0
;
rose
->
state
=
ROSE_STATE_3
;
rose_requeue_frames
(
sk
);
break
;
case
ROSE_CLEAR_REQUEST
:
rose_write_internal
(
sk
,
ROSE_CLEAR_CONFIRMATION
);
rose_disconnect
(
sk
,
0
,
skb
->
data
[
3
],
skb
->
data
[
4
]);
rose
->
neighbour
->
use
--
;
break
;
default:
break
;
}
}
return
0
;
return
0
;
...
@@ -288,21 +273,21 @@ int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb)
...
@@ -288,21 +273,21 @@ int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb)
frametype
=
rose_decode
(
skb
,
&
ns
,
&
nr
,
&
q
,
&
d
,
&
m
);
frametype
=
rose_decode
(
skb
,
&
ns
,
&
nr
,
&
q
,
&
d
,
&
m
);
switch
(
rose
->
state
)
{
switch
(
rose
->
state
)
{
case
ROSE_STATE_1
:
case
ROSE_STATE_1
:
queued
=
rose_state1_machine
(
sk
,
skb
,
frametype
);
queued
=
rose_state1_machine
(
sk
,
skb
,
frametype
);
break
;
break
;
case
ROSE_STATE_2
:
case
ROSE_STATE_2
:
queued
=
rose_state2_machine
(
sk
,
skb
,
frametype
);
queued
=
rose_state2_machine
(
sk
,
skb
,
frametype
);
break
;
break
;
case
ROSE_STATE_3
:
case
ROSE_STATE_3
:
queued
=
rose_state3_machine
(
sk
,
skb
,
frametype
,
ns
,
nr
,
q
,
d
,
m
);
queued
=
rose_state3_machine
(
sk
,
skb
,
frametype
,
ns
,
nr
,
q
,
d
,
m
);
break
;
break
;
case
ROSE_STATE_4
:
case
ROSE_STATE_4
:
queued
=
rose_state4_machine
(
sk
,
skb
,
frametype
);
queued
=
rose_state4_machine
(
sk
,
skb
,
frametype
);
break
;
break
;
case
ROSE_STATE_5
:
case
ROSE_STATE_5
:
queued
=
rose_state5_machine
(
sk
,
skb
,
frametype
);
queued
=
rose_state5_machine
(
sk
,
skb
,
frametype
);
break
;
break
;
}
}
rose_kick
(
sk
);
rose_kick
(
sk
);
...
...
net/rose/rose_link.c
View file @
b331768e
/*
/*
* 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.
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from rose_timer.c
* ROSE 003 Jonathan(G4KLX) New timer architecture.
*/
*/
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
...
@@ -142,25 +134,25 @@ void rose_link_rx_restart(struct sk_buff *skb, struct rose_neigh *neigh, unsigne
...
@@ -142,25 +134,25 @@ void rose_link_rx_restart(struct sk_buff *skb, struct rose_neigh *neigh, unsigne
struct
sk_buff
*
skbn
;
struct
sk_buff
*
skbn
;
switch
(
frametype
)
{
switch
(
frametype
)
{
case
ROSE_RESTART_REQUEST
:
case
ROSE_RESTART_REQUEST
:
rose_stop_t0timer
(
neigh
);
rose_stop_t0timer
(
neigh
);
neigh
->
restarted
=
1
;
neigh
->
restarted
=
1
;
neigh
->
dce_mode
=
(
skb
->
data
[
3
]
==
ROSE_DTE_ORIGINATED
);
neigh
->
dce_mode
=
(
skb
->
data
[
3
]
==
ROSE_DTE_ORIGINATED
);
rose_transmit_restart_confirmation
(
neigh
);
rose_transmit_restart_confirmation
(
neigh
);
break
;
break
;
case
ROSE_RESTART_CONFIRMATION
:
case
ROSE_RESTART_CONFIRMATION
:
rose_stop_t0timer
(
neigh
);
rose_stop_t0timer
(
neigh
);
neigh
->
restarted
=
1
;
neigh
->
restarted
=
1
;
break
;
break
;
case
ROSE_DIAGNOSTIC
:
case
ROSE_DIAGNOSTIC
:
printk
(
KERN_WARNING
"ROSE: received diagnostic #%d - %02X %02X %02X
\n
"
,
skb
->
data
[
3
],
skb
->
data
[
4
],
skb
->
data
[
5
],
skb
->
data
[
6
]);
printk
(
KERN_WARNING
"ROSE: received diagnostic #%d - %02X %02X %02X
\n
"
,
skb
->
data
[
3
],
skb
->
data
[
4
],
skb
->
data
[
5
],
skb
->
data
[
6
]);
break
;
break
;
default:
default:
printk
(
KERN_WARNING
"ROSE: received unknown %02X with LCI 000
\n
"
,
frametype
);
printk
(
KERN_WARNING
"ROSE: received unknown %02X with LCI 000
\n
"
,
frametype
);
break
;
break
;
}
}
if
(
neigh
->
restarted
)
{
if
(
neigh
->
restarted
)
{
...
...
net/rose/rose_loopback.c
View file @
b331768e
/*
/*
* 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
* This code REQUIRES 2.1.15 or higher/ NET3.038
* the Free Software Foundation; either version 2 of the License, or
*
* (at your option) any later version.
* 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.
*
*
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
*/
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
#include <linux/timer.h>
#include <linux/timer.h>
...
...
net/rose/rose_out.c
View file @
b331768e
/*
/*
* 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.
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from nr_out.c
* ROSE 003 Jonathan(G4KLX) New timer architecture.
* Removed M bit processing.
*/
*/
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
...
@@ -36,7 +27,7 @@
...
@@ -36,7 +27,7 @@
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <net/rose.h>
#include <net/rose.h>
/*
/*
* This procedure is passed a buffer descriptor for an iframe. It builds
* This procedure is passed a buffer descriptor for an iframe. It builds
* the rest of the control part of the frame and then writes it out.
* the rest of the control part of the frame and then writes it out.
*/
*/
...
@@ -52,7 +43,7 @@ static void rose_send_iframe(struct sock *sk, struct sk_buff *skb)
...
@@ -52,7 +43,7 @@ static void rose_send_iframe(struct sock *sk, struct sk_buff *skb)
rose_start_idletimer
(
sk
);
rose_start_idletimer
(
sk
);
rose_transmit_link
(
skb
,
rose
->
neighbour
);
rose_transmit_link
(
skb
,
rose
->
neighbour
);
}
}
void
rose_kick
(
struct
sock
*
sk
)
void
rose_kick
(
struct
sock
*
sk
)
...
...
net/rose/rose_route.c
View file @
b331768e
/*
/*
* 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)
*
* Copyright (C) Terry Dawson VK2KTJ (terry@animats.net)
* 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.
*/
*/
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
...
@@ -51,8 +39,11 @@
...
@@ -51,8 +39,11 @@
static
unsigned
int
rose_neigh_no
=
1
;
static
unsigned
int
rose_neigh_no
=
1
;
static
struct
rose_node
*
rose_node_list
;
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
struct
rose_neigh
*
rose_neigh_list
;
static
spinlock_t
rose_neigh_list_lock
=
SPIN_LOCK_UNLOCKED
;
static
struct
rose_route
*
rose_route_list
;
static
struct
rose_route
*
rose_route_list
;
static
spinlock_t
rose_route_list_lock
=
SPIN_LOCK_UNLOCKED
;
struct
rose_neigh
*
rose_loopback_neigh
;
struct
rose_neigh
*
rose_loopback_neigh
;
...
@@ -62,27 +53,44 @@ static void rose_remove_neigh(struct rose_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
* Add a new route to a node, and in the process add the node and the
* neighbour if it is new.
* 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_node
*
rose_node
,
*
rose_tmpn
,
*
rose_tmpp
;
struct
rose_neigh
*
rose_neigh
;
struct
rose_neigh
*
rose_neigh
;
unsigned
long
flags
;
int
i
,
res
=
0
;
int
i
;
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
)
rose_node
=
rose_node_list
;
if
((
rose_node
->
mask
==
rose_route
->
mask
)
&&
(
rosecmpm
(
&
rose_route
->
address
,
&
rose_node
->
address
,
rose_route
->
mask
)
==
0
))
while
(
rose_node
!=
NULL
)
{
if
((
rose_node
->
mask
==
rose_route
->
mask
)
&&
(
rosecmpm
(
&
rose_route
->
address
,
&
rose_node
->
address
,
rose_route
->
mask
)
==
0
))
break
;
break
;
rose_node
=
rose_node
->
next
;
}
if
(
rose_node
!=
NULL
&&
rose_node
->
loopback
)
if
(
rose_node
!=
NULL
&&
rose_node
->
loopback
)
{
return
-
EINVAL
;
res
=
-
EINVAL
;
goto
out
;
}
for
(
rose_neigh
=
rose_neigh_list
;
rose_neigh
!=
NULL
;
rose_neigh
=
rose_neigh
->
next
)
rose_neigh
=
rose_neigh_list
;
if
(
ax25cmp
(
&
rose_route
->
neighbour
,
&
rose_neigh
->
callsign
)
==
0
&&
rose_neigh
->
dev
==
dev
)
while
(
rose_neigh
!=
NULL
)
{
if
(
ax25cmp
(
&
rose_route
->
neighbour
,
&
rose_neigh
->
callsign
)
==
0
&&
rose_neigh
->
dev
==
dev
)
break
;
break
;
rose_neigh
=
rose_neigh
->
next
;
}
if
(
rose_neigh
==
NULL
)
{
if
(
rose_neigh
==
NULL
)
{
if
((
rose_neigh
=
kmalloc
(
sizeof
(
*
rose_neigh
),
GFP_ATOMIC
))
==
NULL
)
rose_neigh
=
kmalloc
(
sizeof
(
*
rose_neigh
),
GFP_ATOMIC
);
return
-
ENOMEM
;
if
(
rose_neigh
==
NULL
)
{
res
=
-
ENOMEM
;
goto
out
;
}
rose_neigh
->
callsign
=
rose_route
->
neighbour
;
rose_neigh
->
callsign
=
rose_route
->
neighbour
;
rose_neigh
->
digipeat
=
NULL
;
rose_neigh
->
digipeat
=
NULL
;
...
@@ -103,22 +111,22 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
...
@@ -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_route
->
ndigis
!=
0
)
{
if
((
rose_neigh
->
digipeat
=
kmalloc
(
sizeof
(
ax25_digi
),
GFP_KERNEL
))
==
NULL
)
{
if
((
rose_neigh
->
digipeat
=
kmalloc
(
sizeof
(
ax25_digi
),
GFP_KERNEL
))
==
NULL
)
{
kfree
(
rose_neigh
);
kfree
(
rose_neigh
);
return
-
ENOMEM
;
res
=
-
ENOMEM
;
goto
out
;
}
}
rose_neigh
->
digipeat
->
ndigi
=
rose_route
->
ndigis
;
rose_neigh
->
digipeat
->
ndigi
=
rose_route
->
ndigis
;
rose_neigh
->
digipeat
->
lastrepeat
=
-
1
;
rose_neigh
->
digipeat
->
lastrepeat
=
-
1
;
for
(
i
=
0
;
i
<
rose_route
->
ndigis
;
i
++
)
{
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
;
rose_neigh
->
digipeat
->
repeated
[
i
]
=
0
;
}
}
}
}
save_flags
(
flags
);
cli
();
rose_neigh
->
next
=
rose_neigh_list
;
rose_neigh
->
next
=
rose_neigh_list
;
rose_neigh_list
=
rose_neigh
;
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
...
@@ -142,8 +150,11 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
}
}
/* create new node */
/* create new node */
if
((
rose_node
=
kmalloc
(
sizeof
(
*
rose_node
),
GFP_ATOMIC
))
==
NULL
)
rose_node
=
kmalloc
(
sizeof
(
*
rose_node
),
GFP_ATOMIC
);
return
-
ENOMEM
;
if
(
rose_node
==
NULL
)
{
res
=
-
ENOMEM
;
goto
out
;
}
rose_node
->
address
=
rose_route
->
address
;
rose_node
->
address
=
rose_route
->
address
;
rose_node
->
mask
=
rose_route
->
mask
;
rose_node
->
mask
=
rose_route
->
mask
;
...
@@ -151,8 +162,6 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
...
@@ -151,8 +162,6 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
rose_node
->
loopback
=
0
;
rose_node
->
loopback
=
0
;
rose_node
->
neighbour
[
0
]
=
rose_neigh
;
rose_node
->
neighbour
[
0
]
=
rose_neigh
;
save_flags
(
flags
);
cli
();
if
(
rose_tmpn
==
NULL
)
{
if
(
rose_tmpn
==
NULL
)
{
if
(
rose_tmpp
==
NULL
)
{
/* Empty list */
if
(
rose_tmpp
==
NULL
)
{
/* Empty list */
rose_node_list
=
rose_node
;
rose_node_list
=
rose_node
;
...
@@ -170,12 +179,9 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
...
@@ -170,12 +179,9 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
rose_node
->
next
=
rose_tmpn
;
rose_node
->
next
=
rose_tmpn
;
}
}
}
}
restore_flags
(
flags
);
rose_neigh
->
count
++
;
rose_neigh
->
count
++
;
return
0
;
goto
out
;
}
}
/* We have space, slot it in */
/* We have space, slot it in */
...
@@ -185,20 +191,23 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
...
@@ -185,20 +191,23 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
rose_neigh
->
count
++
;
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
)
static
void
rose_remove_node
(
struct
rose_node
*
rose_node
)
{
{
struct
rose_node
*
s
;
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
)
{
if
((
s
=
rose_node_list
)
==
rose_node
)
{
rose_node_list
=
rose_node
->
next
;
rose_node_list
=
rose_node
->
next
;
restore_flags
(
flags
);
kfree
(
rose_node
);
kfree
(
rose_node
);
return
;
return
;
}
}
...
@@ -206,32 +215,31 @@ static void rose_remove_node(struct rose_node *rose_node)
...
@@ -206,32 +215,31 @@ static void rose_remove_node(struct rose_node *rose_node)
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
if
(
s
->
next
==
rose_node
)
{
if
(
s
->
next
==
rose_node
)
{
s
->
next
=
rose_node
->
next
;
s
->
next
=
rose_node
->
next
;
restore_flags
(
flags
);
kfree
(
rose_node
);
kfree
(
rose_node
);
return
;
return
;
}
}
s
=
s
->
next
;
s
=
s
->
next
;
}
}
restore_flags
(
flags
);
}
}
/*
* Caller is holding rose_neigh_list_lock.
*/
static
void
rose_remove_neigh
(
struct
rose_neigh
*
rose_neigh
)
static
void
rose_remove_neigh
(
struct
rose_neigh
*
rose_neigh
)
{
{
struct
rose_neigh
*
s
;
struct
rose_neigh
*
s
;
unsigned
long
flags
;
rose_stop_ftimer
(
rose_neigh
);
rose_stop_ftimer
(
rose_neigh
);
rose_stop_t0timer
(
rose_neigh
);
rose_stop_t0timer
(
rose_neigh
);
skb_queue_purge
(
&
rose_neigh
->
queue
);
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
)
{
if
((
s
=
rose_neigh_list
)
==
rose_neigh
)
{
rose_neigh_list
=
rose_neigh
->
next
;
rose_neigh_list
=
rose_neigh
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
rose_neigh_list_lock
);
if
(
rose_neigh
->
digipeat
!=
NULL
)
if
(
rose_neigh
->
digipeat
!=
NULL
)
kfree
(
rose_neigh
->
digipeat
);
kfree
(
rose_neigh
->
digipeat
);
kfree
(
rose_neigh
);
kfree
(
rose_neigh
);
...
@@ -241,7 +249,7 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
...
@@ -241,7 +249,7 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
if
(
s
->
next
==
rose_neigh
)
{
if
(
s
->
next
==
rose_neigh
)
{
s
->
next
=
rose_neigh
->
next
;
s
->
next
=
rose_neigh
->
next
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
rose_neigh_list_lock
);
if
(
rose_neigh
->
digipeat
!=
NULL
)
if
(
rose_neigh
->
digipeat
!=
NULL
)
kfree
(
rose_neigh
->
digipeat
);
kfree
(
rose_neigh
->
digipeat
);
kfree
(
rose_neigh
);
kfree
(
rose_neigh
);
...
@@ -250,14 +258,15 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
...
@@ -250,14 +258,15 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
s
=
s
->
next
;
s
=
s
->
next
;
}
}
spin_unlock_bh
(
&
rose_neigh_list_lock
);
restore_flags
(
flags
);
}
}
/*
* Caller is holding rose_route_list_lock.
*/
static
void
rose_remove_route
(
struct
rose_route
*
rose_route
)
static
void
rose_remove_route
(
struct
rose_route
*
rose_route
)
{
{
struct
rose_route
*
s
;
struct
rose_route
*
s
;
unsigned
long
flags
;
if
(
rose_route
->
neigh1
!=
NULL
)
if
(
rose_route
->
neigh1
!=
NULL
)
rose_route
->
neigh1
->
use
--
;
rose_route
->
neigh1
->
use
--
;
...
@@ -265,11 +274,8 @@ static void rose_remove_route(struct rose_route *rose_route)
...
@@ -265,11 +274,8 @@ static void rose_remove_route(struct rose_route *rose_route)
if
(
rose_route
->
neigh2
!=
NULL
)
if
(
rose_route
->
neigh2
!=
NULL
)
rose_route
->
neigh2
->
use
--
;
rose_route
->
neigh2
->
use
--
;
save_flags
(
flags
);
cli
();
if
((
s
=
rose_route_list
)
==
rose_route
)
{
if
((
s
=
rose_route_list
)
==
rose_route
)
{
rose_route_list
=
rose_route
->
next
;
rose_route_list
=
rose_route
->
next
;
restore_flags
(
flags
);
kfree
(
rose_route
);
kfree
(
rose_route
);
return
;
return
;
}
}
...
@@ -277,40 +283,54 @@ static void rose_remove_route(struct rose_route *rose_route)
...
@@ -277,40 +283,54 @@ static void rose_remove_route(struct rose_route *rose_route)
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
while
(
s
!=
NULL
&&
s
->
next
!=
NULL
)
{
if
(
s
->
next
==
rose_route
)
{
if
(
s
->
next
==
rose_route
)
{
s
->
next
=
rose_route
->
next
;
s
->
next
=
rose_route
->
next
;
restore_flags
(
flags
);
kfree
(
rose_route
);
kfree
(
rose_route
);
return
;
return
;
}
}
s
=
s
->
next
;
s
=
s
->
next
;
}
}
restore_flags
(
flags
);
}
}
/*
/*
* "Delete" a node. Strictly speaking remove a route to a node. The node
* "Delete" a node. Strictly speaking remove a route to a node. The node
* is only deleted if no routes are left to it.
* 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_node
*
rose_node
;
struct
rose_neigh
*
rose_neigh
;
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
)
spin_lock_bh
(
&
rose_node_list_lock
);
if
((
rose_node
->
mask
==
rose_route
->
mask
)
&&
(
rosecmpm
(
&
rose_route
->
address
,
&
rose_node
->
address
,
rose_route
->
mask
)
==
0
))
spin_lock_bh
(
&
rose_neigh_list_lock
);
break
;
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
)
rose_neigh
=
rose_neigh_list
;
if
(
ax25cmp
(
&
rose_route
->
neighbour
,
&
rose_neigh
->
callsign
)
==
0
&&
rose_neigh
->
dev
==
dev
)
while
(
rose_neigh
!=
NULL
)
{
if
(
ax25cmp
(
&
rose_route
->
neighbour
,
&
rose_neigh
->
callsign
)
==
0
&&
rose_neigh
->
dev
==
dev
)
break
;
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
++
)
{
for
(
i
=
0
;
i
<
rose_node
->
count
;
i
++
)
{
if
(
rose_node
->
neighbour
[
i
]
==
rose_neigh
)
{
if
(
rose_node
->
neighbour
[
i
]
==
rose_neigh
)
{
...
@@ -325,20 +345,26 @@ static int rose_del_node(struct rose_route_struct *rose_route, struct net_device
...
@@ -325,20 +345,26 @@ static int rose_del_node(struct rose_route_struct *rose_route, struct net_device
rose_remove_node
(
rose_node
);
rose_remove_node
(
rose_node
);
}
else
{
}
else
{
switch
(
i
)
{
switch
(
i
)
{
case
0
:
case
0
:
rose_node
->
neighbour
[
0
]
=
rose_node
->
neighbour
[
1
];
rose_node
->
neighbour
[
0
]
=
case
1
:
rose_node
->
neighbour
[
1
];
rose_node
->
neighbour
[
1
]
=
rose_node
->
neighbour
[
2
];
case
1
:
case
2
:
rose_node
->
neighbour
[
1
]
=
break
;
rose_node
->
neighbour
[
2
];
case
2
:
break
;
}
}
}
}
goto
out
;
return
0
;
}
}
}
}
err
=
-
EINVAL
;
out:
spin_unlock_bh
(
&
rose_neigh_list_lock
);
spin_unlock_bh
(
&
rose_node_list_lock
);
return
-
EINVAL
;
return
err
;
}
}
/*
/*
...
@@ -346,8 +372,6 @@ static int rose_del_node(struct rose_route_struct *rose_route, struct net_device
...
@@ -346,8 +372,6 @@ static int rose_del_node(struct rose_route_struct *rose_route, struct net_device
*/
*/
int
rose_add_loopback_neigh
(
void
)
int
rose_add_loopback_neigh
(
void
)
{
{
unsigned
long
flags
;
if
((
rose_loopback_neigh
=
kmalloc
(
sizeof
(
struct
rose_neigh
),
GFP_ATOMIC
))
==
NULL
)
if
((
rose_loopback_neigh
=
kmalloc
(
sizeof
(
struct
rose_neigh
),
GFP_ATOMIC
))
==
NULL
)
return
-
ENOMEM
;
return
-
ENOMEM
;
...
@@ -367,10 +391,10 @@ int rose_add_loopback_neigh(void)
...
@@ -367,10 +391,10 @@ int rose_add_loopback_neigh(void)
init_timer
(
&
rose_loopback_neigh
->
ftimer
);
init_timer
(
&
rose_loopback_neigh
->
ftimer
);
init_timer
(
&
rose_loopback_neigh
->
t0timer
);
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_loopback_neigh
->
next
=
rose_neigh_list
;
rose_neigh_list
=
rose_loopback_neigh
;
rose_neigh_list
=
rose_loopback_neigh
;
restore_flags
(
flags
);
spin_unlock_bh
(
&
rose_neigh_list_lock
);
return
0
;
return
0
;
}
}
...
@@ -381,16 +405,26 @@ int rose_add_loopback_neigh(void)
...
@@ -381,16 +405,26 @@ int rose_add_loopback_neigh(void)
int
rose_add_loopback_node
(
rose_address
*
address
)
int
rose_add_loopback_node
(
rose_address
*
address
)
{
{
struct
rose_node
*
rose_node
;
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
)
spin_lock_bh
(
&
rose_node_list_lock
);
if
((
rose_node
->
mask
==
10
)
&&
(
rosecmpm
(
address
,
&
rose_node
->
address
,
10
)
==
0
)
&&
rose_node
->
loopback
)
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
;
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
->
address
=
*
address
;
rose_node
->
mask
=
10
;
rose_node
->
mask
=
10
;
...
@@ -399,13 +433,14 @@ int rose_add_loopback_node(rose_address *address)
...
@@ -399,13 +433,14 @@ int rose_add_loopback_node(rose_address *address)
rose_node
->
neighbour
[
0
]
=
rose_loopback_neigh
;
rose_node
->
neighbour
[
0
]
=
rose_loopback_neigh
;
/* Insert at the head of list. Address is always mask=10 */
/* Insert at the head of list. Address is always mask=10 */
save_flags
(
flags
);
cli
();
rose_node
->
next
=
rose_node_list
;
rose_node
->
next
=
rose_node_list
;
rose_node_list
=
rose_node
;
rose_node_list
=
rose_node
;
restore_flags
(
flags
);
rose_loopback_neigh
->
count
++
;
rose_loopback_neigh
->
count
++
;
out:
spin_unlock_bh
(
&
rose_node_list_lock
);
return
0
;
return
0
;
}
}
...
@@ -416,15 +451,26 @@ void rose_del_loopback_node(rose_address *address)
...
@@ -416,15 +451,26 @@ void rose_del_loopback_node(rose_address *address)
{
{
struct
rose_node
*
rose_node
;
struct
rose_node
*
rose_node
;
for
(
rose_node
=
rose_node_list
;
rose_node
!=
NULL
;
rose_node
=
rose_node
->
next
)
spin_lock_bh
(
&
rose_node_list_lock
);
if
((
rose_node
->
mask
==
10
)
&&
(
rosecmpm
(
address
,
&
rose_node
->
address
,
10
)
==
0
)
&&
rose_node
->
loopback
)
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
;
break
;
rose_node
=
rose_node
->
next
;
}
if
(
rose_node
==
NULL
)
return
;
if
(
rose_node
==
NULL
)
goto
out
;
rose_remove_node
(
rose_node
);
rose_remove_node
(
rose_node
);
rose_loopback_neigh
->
count
--
;
rose_loopback_neigh
->
count
--
;
out:
spin_unlock_bh
(
&
rose_node_list_lock
);
}
}
/*
/*
...
@@ -432,52 +478,62 @@ void rose_del_loopback_node(rose_address *address)
...
@@ -432,52 +478,62 @@ void rose_del_loopback_node(rose_address *address)
*/
*/
void
rose_rt_device_down
(
struct
net_device
*
dev
)
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
;
struct
rose_node
*
t
,
*
rose_node
;
int
i
;
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
)
{
while
(
rose_neigh
!=
NULL
)
{
s
=
rose_neigh
;
s
=
rose_neigh
;
rose_neigh
=
rose_neigh
->
next
;
rose_neigh
=
rose_neigh
->
next
;
if
(
s
->
dev
==
dev
)
{
if
(
s
->
dev
!=
dev
)
rose_node
=
rose_node_list
;
continue
;
while
(
rose_node
!=
NULL
)
{
rose_node
=
rose_node_list
;
t
=
rose_node
;
rose_node
=
rose_node
->
next
;
while
(
rose_node
!=
NULL
)
{
t
=
rose_node
;
for
(
i
=
0
;
i
<
t
->
count
;
i
++
)
{
rose_node
=
rose_node
->
next
;
if
(
t
->
neighbour
[
i
]
==
s
)
{
t
->
count
--
;
for
(
i
=
0
;
i
<
t
->
count
;
i
++
)
{
if
(
t
->
neighbour
[
i
]
!=
s
)
switch
(
i
)
{
continue
;
case
0
:
t
->
neighbour
[
0
]
=
t
->
neighbour
[
1
];
t
->
count
--
;
case
1
:
t
->
neighbour
[
1
]
=
t
->
neighbour
[
2
];
case
2
:
break
;
}
}
}
if
(
t
->
count
<=
0
)
switch
(
i
)
{
rose_remove_node
(
t
);
case
0
:
t
->
neighbour
[
0
]
=
t
->
neighbour
[
1
];
case
1
:
t
->
neighbour
[
1
]
=
t
->
neighbour
[
2
];
case
2
:
break
;
}
}
}
rose_remove_neigh
(
s
);
if
(
t
->
count
<=
0
)
rose_remove_node
(
t
);
}
}
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.
* A device has been removed. Remove its links.
*/
*/
void rose_route_device_down(struct net_device *dev)
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) {
while (rose_route != NULL) {
s = rose_route;
s = rose_route;
rose_route = rose_route->next;
rose_route = rose_route->next;
...
@@ -485,7 +541,9 @@ void rose_route_device_down(struct net_device *dev)
...
@@ -485,7 +541,9 @@ void rose_route_device_down(struct net_device *dev)
if (s->neigh1->dev == dev || s->neigh2->dev == dev)
if (s->neigh1->dev == dev || s->neigh2->dev == dev)
rose_remove_route(s);
rose_remove_route(s);
}
}
spin_unlock_bh(&rose_route_list_lock);
}
}
#endif
/*
/*
* Clear all nodes and neighbours out, except for neighbours with
* Clear all nodes and neighbours out, except for neighbours with
...
@@ -494,8 +552,14 @@ void rose_route_device_down(struct net_device *dev)
...
@@ -494,8 +552,14 @@ void rose_route_device_down(struct net_device *dev)
*/
*/
static
int
rose_clear_routes
(
void
)
static
int
rose_clear_routes
(
void
)
{
{
struct
rose_neigh
*
s
,
*
rose_neigh
=
rose_neigh_list
;
struct
rose_neigh
*
s
,
*
rose_neigh
;
struct
rose_node
*
t
,
*
rose_node
=
rose_node_list
;
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
)
{
while
(
rose_node
!=
NULL
)
{
t
=
rose_node
;
t
=
rose_node
;
...
@@ -514,6 +578,9 @@ static int rose_clear_routes(void)
...
@@ -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
;
return
0
;
}
}
...
@@ -603,18 +670,22 @@ struct rose_route *rose_route_free_lci(unsigned int lci, struct rose_neigh *neig
...
@@ -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.
* 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
;
struct
rose_node
*
node
;
int
failed
=
0
;
int
failed
=
0
;
int
i
;
int
i
;
spin_lock_bh
(
&
rose_node_list_lock
);
for
(
node
=
rose_node_list
;
node
!=
NULL
;
node
=
node
->
next
)
{
for
(
node
=
rose_node_list
;
node
!=
NULL
;
node
=
node
->
next
)
{
if
(
rosecmpm
(
addr
,
&
node
->
address
,
node
->
mask
)
==
0
)
{
if
(
rosecmpm
(
addr
,
&
node
->
address
,
node
->
mask
)
==
0
)
{
for
(
i
=
0
;
i
<
node
->
count
;
i
++
)
{
for
(
i
=
0
;
i
<
node
->
count
;
i
++
)
{
if
(
!
rose_ftimer_running
(
node
->
neighbour
[
i
]))
{
if
(
!
rose_ftimer_running
(
node
->
neighbour
[
i
]))
{
return
node
->
neighbour
[
i
];
}
res
=
node
->
neighbour
[
i
];
else
goto
out
;
}
else
failed
=
1
;
failed
=
1
;
}
}
break
;
break
;
...
@@ -629,7 +700,10 @@ struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, unsi
...
@@ -629,7 +700,10 @@ struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, unsi
*
diagnostic
=
0
;
*
diagnostic
=
0
;
}
}
return
NULL
;
out:
spin_unlock_bh
(
&
rose_node_list_lock
);
return
res
;
}
}
/*
/*
...
@@ -642,38 +716,36 @@ int rose_rt_ioctl(unsigned int cmd, void *arg)
...
@@ -642,38 +716,36 @@ int rose_rt_ioctl(unsigned int cmd, void *arg)
int
err
;
int
err
;
switch
(
cmd
)
{
switch
(
cmd
)
{
case
SIOCADDRT
:
case
SIOCADDRT
:
if
(
copy_from_user
(
&
rose_route
,
arg
,
sizeof
(
struct
rose_route_struct
)))
if
(
copy_from_user
(
&
rose_route
,
arg
,
sizeof
(
struct
rose_route_struct
)))
return
-
EFAULT
;
return
-
EFAULT
;
if
((
dev
=
rose_ax25_dev_get
(
rose_route
.
device
))
==
NULL
)
if
((
dev
=
rose_ax25_dev_get
(
rose_route
.
device
))
==
NULL
)
return
-
EINVAL
;
return
-
EINVAL
;
if
(
rose_dev_exists
(
&
rose_route
.
address
))
{
/* Can't add routes to ourself */
if
(
rose_dev_exists
(
&
rose_route
.
address
))
{
/* Can't add routes to ourself */
dev_put
(
dev
);
return
-
EINVAL
;
}
if
(
rose_route
.
mask
>
10
)
/* Mask can't be more than 10 digits */
return
-
EINVAL
;
err
=
rose_add_node
(
&
rose_route
,
dev
);
dev_put
(
dev
);
return
err
;
case
SIOCDELRT
:
if
(
copy_from_user
(
&
rose_route
,
arg
,
sizeof
(
struct
rose_route_struct
)))
return
-
EFAULT
;
if
((
dev
=
rose_ax25_dev_get
(
rose_route
.
device
))
==
NULL
)
return
-
EINVAL
;
err
=
rose_del_node
(
&
rose_route
,
dev
);
dev_put
(
dev
);
dev_put
(
dev
);
return
err
;
return
-
EINVAL
;
}
if
(
rose_route
.
mask
>
10
)
/* Mask can't be more than 10 digits */
return
-
EINVAL
;
case
SIOCRSCLRRT
:
err
=
rose_add_node
(
&
rose_route
,
dev
);
return
rose_clear_routes
();
dev_put
(
dev
);
return
err
;
default:
case
SIOCDELRT
:
if
(
copy_from_user
(
&
rose_route
,
arg
,
sizeof
(
struct
rose_route_struct
)))
return
-
EFAULT
;
if
((
dev
=
rose_ax25_dev_get
(
rose_route
.
device
))
==
NULL
)
return
-
EINVAL
;
return
-
EINVAL
;
err
=
rose_del_node
(
&
rose_route
,
dev
);
dev_put
(
dev
);
return
err
;
case
SIOCRSCLRRT
:
return
rose_clear_routes
();
default:
return
-
EINVAL
;
}
}
return
0
;
return
0
;
...
@@ -690,6 +762,8 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
...
@@ -690,6 +762,8 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
skb_queue_purge
(
&
rose_neigh
->
queue
);
skb_queue_purge
(
&
rose_neigh
->
queue
);
spin_lock_bh
(
&
rose_route_list_lock
);
rose_route
=
rose_route_list
;
rose_route
=
rose_route_list
;
while
(
rose_route
!=
NULL
)
{
while
(
rose_route
!=
NULL
)
{
...
@@ -716,6 +790,7 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
...
@@ -716,6 +790,7 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
rose_route
=
rose_route
->
next
;
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)
...
@@ -727,16 +802,21 @@ void rose_link_failed(ax25_cb *ax25, int reason)
{
{
struct
rose_neigh
*
rose_neigh
;
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
)
if
(
rose_neigh
->
ax25
==
ax25
)
break
;
break
;
rose_neigh
=
rose_neigh
->
next
;
}
if
(
rose_neigh
==
NULL
)
return
;
if
(
rose_neigh
!=
NULL
)
{
rose_neigh
->
ax25
=
NULL
;
rose_neigh
->
ax25
=
NULL
;
rose_del_route_by_neigh
(
rose_neigh
);
rose_del_route_by_neigh
(
rose_neigh
);
rose_kill_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)
...
@@ -769,12 +849,11 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
unsigned
int
lci
,
new_lci
;
unsigned
int
lci
,
new_lci
;
unsigned
char
cause
,
diagnostic
;
unsigned
char
cause
,
diagnostic
;
struct
net_device
*
dev
;
struct
net_device
*
dev
;
unsigned
long
flags
;
int
len
,
res
=
0
;
int
len
;
#if 0
#if 0
if (call_in_firewall(PF_ROSE, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT)
if (call_in_firewall(PF_ROSE, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT)
return
0
;
return
res
;
#endif
#endif
frametype
=
skb
->
data
[
2
];
frametype
=
skb
->
data
[
2
];
...
@@ -782,13 +861,22 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
...
@@ -782,13 +861,22 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
src_addr
=
(
rose_address
*
)(
skb
->
data
+
9
);
src_addr
=
(
rose_address
*
)(
skb
->
data
+
9
);
dest_addr
=
(
rose_address
*
)(
skb
->
data
+
4
);
dest_addr
=
(
rose_address
*
)(
skb
->
data
+
4
);
for
(
rose_neigh
=
rose_neigh_list
;
rose_neigh
!=
NULL
;
rose_neigh
=
rose_neigh
->
next
)
spin_lock_bh
(
&
rose_node_list_lock
);
if
(
ax25cmp
(
&
ax25
->
dest_addr
,
&
rose_neigh
->
callsign
)
==
0
&&
ax25
->
ax25_dev
->
dev
==
rose_neigh
->
dev
)
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
;
break
;
rose_neigh
=
rose_neigh
->
next
;
}
if
(
rose_neigh
==
NULL
)
{
if
(
rose_neigh
==
NULL
)
{
printk
(
"rose_route : unknown neighbour or device %s
\n
"
,
ax2asc
(
&
ax25
->
dest_addr
));
printk
(
"rose_route : unknown neighbour or device %s
\n
"
,
return
0
;
ax2asc
(
&
ax25
->
dest_addr
));
goto
out
;
}
}
/*
/*
...
@@ -802,7 +890,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
...
@@ -802,7 +890,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
*/
*/
if
(
lci
==
0
)
{
if
(
lci
==
0
)
{
rose_link_rx_restart
(
skb
,
rose_neigh
,
frametype
);
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)
...
@@ -828,7 +916,8 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
}
}
else
{
else
{
skb
->
h
.
raw
=
skb
->
data
;
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)
...
@@ -837,21 +926,23 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
*/
*/
if
(
frametype
==
ROSE_CALL_REQUEST
)
if
(
frametype
==
ROSE_CALL_REQUEST
)
if
((
dev
=
rose_dev_get
(
dest_addr
))
!=
NULL
)
{
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
);
dev_put
(
dev
);
return
err
;
goto
out
;
}
}
if
(
!
sysctl_rose_routing_control
)
{
if
(
!
sysctl_rose_routing_control
)
{
rose_transmit_clear_request
(
rose_neigh
,
lci
,
ROSE_NOT_OBTAINABLE
,
0
);
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.
* 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
)
{
rose_route
=
rose_route_list
;
if
(
rose_route
->
lci1
==
lci
&&
rose_route
->
neigh1
==
rose_neigh
)
{
while
(
rose_route
!=
NULL
)
{
if
(
rose_route
->
lci1
==
lci
&&
rose_route
->
neigh1
==
rose_neigh
)
{
if
(
frametype
==
ROSE_CALL_REQUEST
)
{
if
(
frametype
==
ROSE_CALL_REQUEST
)
{
/* F6FBB - Remove an existing unused route */
/* F6FBB - Remove an existing unused route */
rose_remove_route
(
rose_route
);
rose_remove_route
(
rose_route
);
...
@@ -863,14 +954,16 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
...
@@ -863,14 +954,16 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
rose_transmit_link
(
skb
,
rose_route
->
neigh2
);
rose_transmit_link
(
skb
,
rose_route
->
neigh2
);
if
(
frametype
==
ROSE_CLEAR_CONFIRMATION
)
if
(
frametype
==
ROSE_CLEAR_CONFIRMATION
)
rose_remove_route
(
rose_route
);
rose_remove_route
(
rose_route
);
return
1
;
res
=
1
;
goto
out
;
}
else
{
}
else
{
if
(
frametype
==
ROSE_CLEAR_CONFIRMATION
)
if
(
frametype
==
ROSE_CLEAR_CONFIRMATION
)
rose_remove_route
(
rose_route
);
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
)
{
if
(
frametype
==
ROSE_CALL_REQUEST
)
{
/* F6FBB - Remove an existing unused route */
/* F6FBB - Remove an existing unused route */
rose_remove_route
(
rose_route
);
rose_remove_route
(
rose_route
);
...
@@ -882,13 +975,15 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
...
@@ -882,13 +975,15 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
rose_transmit_link
(
skb
,
rose_route
->
neigh1
);
rose_transmit_link
(
skb
,
rose_route
->
neigh1
);
if
(
frametype
==
ROSE_CLEAR_CONFIRMATION
)
if
(
frametype
==
ROSE_CLEAR_CONFIRMATION
)
rose_remove_route
(
rose_route
);
rose_remove_route
(
rose_route
);
return
1
;
res
=
1
;
goto
out
;
}
else
{
}
else
{
if
(
frametype
==
ROSE_CLEAR_CONFIRMATION
)
if
(
frametype
==
ROSE_CLEAR_CONFIRMATION
)
rose_remove_route
(
rose_route
);
rose_remove_route
(
rose_route
);
return
0
;
goto
out
;
}
}
}
}
rose_route
=
rose_route
->
next
;
}
}
/*
/*
...
@@ -903,38 +998,40 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
...
@@ -903,38 +998,40 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
len
+=
(((
skb
->
data
[
3
]
>>
0
)
&
0x0F
)
+
1
)
/
2
;
len
+=
(((
skb
->
data
[
3
]
>>
0
)
&
0x0F
)
+
1
)
/
2
;
memset
(
&
facilities
,
0x00
,
sizeof
(
struct
rose_facilities_struct
));
memset
(
&
facilities
,
0x00
,
sizeof
(
struct
rose_facilities_struct
));
if
(
!
rose_parse_facilities
(
skb
->
data
+
len
+
4
,
&
facilities
))
{
if
(
!
rose_parse_facilities
(
skb
->
data
+
len
+
4
,
&
facilities
))
{
rose_transmit_clear_request
(
rose_neigh
,
lci
,
ROSE_INVALID_FACILITY
,
76
);
rose_transmit_clear_request
(
rose_neigh
,
lci
,
ROSE_INVALID_FACILITY
,
76
);
return
0
;
goto
out
;
}
}
/*
/*
* Check for routing loops.
* 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
&&
if
(
rose_route
->
rand
==
facilities
.
rand
&&
rosecmp
(
src_addr
,
&
rose_route
->
src_addr
)
==
0
&&
rosecmp
(
src_addr
,
&
rose_route
->
src_addr
)
==
0
&&
ax25cmp
(
&
facilities
.
dest_call
,
&
rose_route
->
src_call
)
==
0
&&
ax25cmp
(
&
facilities
.
dest_call
,
&
rose_route
->
src_call
)
==
0
&&
ax25cmp
(
&
facilities
.
source_call
,
&
rose_route
->
dest_call
)
==
0
)
{
ax25cmp
(
&
facilities
.
source_call
,
&
rose_route
->
dest_call
)
==
0
)
{
rose_transmit_clear_request
(
rose_neigh
,
lci
,
ROSE_NOT_OBTAINABLE
,
120
);
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
)
{
if
((
new_neigh
=
rose_get_neigh
(
dest_addr
,
&
cause
,
&
diagnostic
))
==
NULL
)
{
rose_transmit_clear_request
(
rose_neigh
,
lci
,
cause
,
diagnostic
);
rose_transmit_clear_request
(
rose_neigh
,
lci
,
cause
,
diagnostic
);
return
0
;
goto
out
;
}
}
if
((
new_lci
=
rose_new_lci
(
new_neigh
))
==
0
)
{
if
((
new_lci
=
rose_new_lci
(
new_neigh
))
==
0
)
{
rose_transmit_clear_request
(
rose_neigh
,
lci
,
ROSE_NETWORK_CONGESTION
,
71
);
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
)
{
if
((
rose_route
=
kmalloc
(
sizeof
(
*
rose_route
),
GFP_ATOMIC
))
==
NULL
)
{
rose_transmit_clear_request
(
rose_neigh
,
lci
,
ROSE_NETWORK_CONGESTION
,
120
);
rose_transmit_clear_request
(
rose_neigh
,
lci
,
ROSE_NETWORK_CONGESTION
,
120
);
return
0
;
goto
out
;
}
}
rose_route
->
lci1
=
lci
;
rose_route
->
lci1
=
lci
;
...
@@ -950,18 +1047,22 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
...
@@ -950,18 +1047,22 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
rose_route
->
neigh1
->
use
++
;
rose_route
->
neigh1
->
use
++
;
rose_route
->
neigh2
->
use
++
;
rose_route
->
neigh2
->
use
++
;
save_flags
(
flags
);
cli
();
rose_route
->
next
=
rose_route_list
;
rose_route
->
next
=
rose_route_list
;
rose_route_list
=
rose_route
;
rose_route_list
=
rose_route
;
restore_flags
(
flags
);
skb
->
data
[
0
]
&=
0xF0
;
skb
->
data
[
0
]
&=
0xF0
;
skb
->
data
[
0
]
|=
(
rose_route
->
lci2
>>
8
)
&
0x0F
;
skb
->
data
[
0
]
|=
(
rose_route
->
lci2
>>
8
)
&
0x0F
;
skb
->
data
[
1
]
=
(
rose_route
->
lci2
>>
0
)
&
0xFF
;
skb
->
data
[
1
]
=
(
rose_route
->
lci2
>>
0
)
&
0xFF
;
rose_transmit_link
(
skb
,
rose_route
->
neigh2
);
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
)
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)
...
@@ -972,7 +1073,7 @@ int rose_nodes_get_info(char *buffer, char **start, off_t offset, int length)
off_t
begin
=
0
;
off_t
begin
=
0
;
int
i
;
int
i
;
cli
(
);
spin_lock_bh
(
&
rose_neigh_list_lock
);
len
+=
sprintf
(
buffer
,
"address mask n neigh neigh neigh
\n
"
);
len
+=
sprintf
(
buffer
,
"address mask n neigh neigh neigh
\n
"
);
...
@@ -1004,16 +1105,16 @@ int rose_nodes_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -1004,16 +1105,16 @@ int rose_nodes_get_info(char *buffer, char **start, off_t offset, int length)
if
(
pos
>
offset
+
length
)
if
(
pos
>
offset
+
length
)
break
;
break
;
}
}
spin_unlock_bh
(
&
rose_neigh_list_lock
);
sti
();
*
start
=
buffer
+
(
offset
-
begin
);
*
start
=
buffer
+
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
if
(
len
>
length
)
len
=
length
;
if
(
len
>
length
)
len
=
length
;
return
len
;
return
len
;
}
}
int
rose_neigh_get_info
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
int
rose_neigh_get_info
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
{
{
...
@@ -1023,7 +1124,7 @@ int rose_neigh_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -1023,7 +1124,7 @@ int rose_neigh_get_info(char *buffer, char **start, off_t offset, int length)
off_t
begin
=
0
;
off_t
begin
=
0
;
int
i
;
int
i
;
cli
(
);
spin_lock_bh
(
&
rose_neigh_list_lock
);
len
+=
sprintf
(
buffer
,
"addr callsign dev count use mode restart t0 tf digipeaters
\n
"
);
len
+=
sprintf
(
buffer
,
"addr callsign dev count use mode restart t0 tf digipeaters
\n
"
);
...
@@ -1059,15 +1160,16 @@ int rose_neigh_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -1059,15 +1160,16 @@ 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
);
*
start
=
buffer
+
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
if
(
len
>
length
)
len
=
length
;
if
(
len
>
length
)
len
=
length
;
return
len
;
return
len
;
}
}
int
rose_routes_get_info
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
int
rose_routes_get_info
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
{
{
...
@@ -1076,7 +1178,7 @@ int rose_routes_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -1076,7 +1178,7 @@ int rose_routes_get_info(char *buffer, char **start, off_t offset, int length)
off_t
pos
=
0
;
off_t
pos
=
0
;
off_t
begin
=
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
"
);
len
+=
sprintf
(
buffer
,
"lci address callsign neigh <-> lci address callsign neigh
\n
"
);
...
@@ -1112,15 +1214,16 @@ int rose_routes_get_info(char *buffer, char **start, off_t offset, int length)
...
@@ -1112,15 +1214,16 @@ int rose_routes_get_info(char *buffer, char **start, off_t offset, int length)
break
;
break
;
}
}
s
ti
(
);
s
pin_unlock_bh
(
&
rose_route_list_lock
);
*
start
=
buffer
+
(
offset
-
begin
);
*
start
=
buffer
+
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
if
(
len
>
length
)
len
=
length
;
if
(
len
>
length
)
len
=
length
;
return
len
;
return
len
;
}
}
/*
/*
* Release all memory associated with ROSE routing structures.
* Release all memory associated with ROSE routing structures.
...
...
net/rose/rose_subr.c
View file @
b331768e
/*
/*
* 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.
*
* 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.
*/
*/
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
...
@@ -103,7 +94,7 @@ int rose_validate_nr(struct sock *sk, unsigned short nr)
...
@@ -103,7 +94,7 @@ int rose_validate_nr(struct sock *sk, unsigned short nr)
return
nr
==
rose
->
vs
;
return
nr
==
rose
->
vs
;
}
}
/*
/*
* This routine is called when the packet layer internally generates a
* This routine is called when the packet layer internally generates a
* control frame.
* control frame.
*/
*/
...
@@ -119,16 +110,16 @@ void rose_write_internal(struct sock *sk, int frametype)
...
@@ -119,16 +110,16 @@ void rose_write_internal(struct sock *sk, int frametype)
len
=
AX25_BPQ_HEADER_LEN
+
AX25_MAX_HEADER_LEN
+
ROSE_MIN_LEN
+
1
;
len
=
AX25_BPQ_HEADER_LEN
+
AX25_MAX_HEADER_LEN
+
ROSE_MIN_LEN
+
1
;
switch
(
frametype
)
{
switch
(
frametype
)
{
case
ROSE_CALL_REQUEST
:
case
ROSE_CALL_REQUEST
:
len
+=
1
+
ROSE_ADDR_LEN
+
ROSE_ADDR_LEN
;
len
+=
1
+
ROSE_ADDR_LEN
+
ROSE_ADDR_LEN
;
faclen
=
rose_create_facilities
(
buffer
,
rose
);
faclen
=
rose_create_facilities
(
buffer
,
rose
);
len
+=
faclen
;
len
+=
faclen
;
break
;
break
;
case
ROSE_CALL_ACCEPTED
:
case
ROSE_CALL_ACCEPTED
:
case
ROSE_CLEAR_REQUEST
:
case
ROSE_CLEAR_REQUEST
:
case
ROSE_RESET_REQUEST
:
case
ROSE_RESET_REQUEST
:
len
+=
2
;
len
+=
2
;
break
;
break
;
}
}
if
((
skb
=
alloc_skb
(
len
,
GFP_ATOMIC
))
==
NULL
)
if
((
skb
=
alloc_skb
(
len
,
GFP_ATOMIC
))
==
NULL
)
...
@@ -138,70 +129,69 @@ void rose_write_internal(struct sock *sk, int frametype)
...
@@ -138,70 +129,69 @@ void rose_write_internal(struct sock *sk, int frametype)
* Space for AX.25 header and PID.
* Space for AX.25 header and PID.
*/
*/
skb_reserve
(
skb
,
AX25_BPQ_HEADER_LEN
+
AX25_MAX_HEADER_LEN
+
1
);
skb_reserve
(
skb
,
AX25_BPQ_HEADER_LEN
+
AX25_MAX_HEADER_LEN
+
1
);
dptr
=
skb_put
(
skb
,
skb_tailroom
(
skb
));
dptr
=
skb_put
(
skb
,
skb_tailroom
(
skb
));
lci1
=
(
rose
->
lci
>>
8
)
&
0x0F
;
lci1
=
(
rose
->
lci
>>
8
)
&
0x0F
;
lci2
=
(
rose
->
lci
>>
0
)
&
0xFF
;
lci2
=
(
rose
->
lci
>>
0
)
&
0xFF
;
switch
(
frametype
)
{
switch
(
frametype
)
{
case
ROSE_CALL_REQUEST
:
case
ROSE_CALL_REQUEST
:
*
dptr
++
=
ROSE_GFI
|
lci1
;
*
dptr
++
=
ROSE_GFI
|
lci1
;
*
dptr
++
=
lci2
;
*
dptr
++
=
lci2
;
*
dptr
++
=
frametype
;
*
dptr
++
=
frametype
;
*
dptr
++
=
0xAA
;
*
dptr
++
=
0xAA
;
memcpy
(
dptr
,
&
rose
->
dest_addr
,
ROSE_ADDR_LEN
);
memcpy
(
dptr
,
&
rose
->
dest_addr
,
ROSE_ADDR_LEN
);
dptr
+=
ROSE_ADDR_LEN
;
dptr
+=
ROSE_ADDR_LEN
;
memcpy
(
dptr
,
&
rose
->
source_addr
,
ROSE_ADDR_LEN
);
memcpy
(
dptr
,
&
rose
->
source_addr
,
ROSE_ADDR_LEN
);
dptr
+=
ROSE_ADDR_LEN
;
dptr
+=
ROSE_ADDR_LEN
;
memcpy
(
dptr
,
buffer
,
faclen
);
memcpy
(
dptr
,
buffer
,
faclen
);
dptr
+=
faclen
;
dptr
+=
faclen
;
break
;
break
;
case
ROSE_CALL_ACCEPTED
:
case
ROSE_CALL_ACCEPTED
:
*
dptr
++
=
ROSE_GFI
|
lci1
;
*
dptr
++
=
ROSE_GFI
|
lci1
;
*
dptr
++
=
lci2
;
*
dptr
++
=
lci2
;
*
dptr
++
=
frametype
;
*
dptr
++
=
frametype
;
*
dptr
++
=
0x00
;
/* Address length */
*
dptr
++
=
0x00
;
/* Address length */
*
dptr
++
=
0
;
/* Facilities length */
*
dptr
++
=
0
;
/* Facilities length */
break
;
break
;
case
ROSE_CLEAR_REQUEST
:
case
ROSE_CLEAR_REQUEST
:
*
dptr
++
=
ROSE_GFI
|
lci1
;
*
dptr
++
=
ROSE_GFI
|
lci1
;
*
dptr
++
=
lci2
;
*
dptr
++
=
lci2
;
*
dptr
++
=
frametype
;
*
dptr
++
=
frametype
;
*
dptr
++
=
rose
->
cause
;
*
dptr
++
=
rose
->
cause
;
*
dptr
++
=
rose
->
diagnostic
;
*
dptr
++
=
rose
->
diagnostic
;
break
;
break
;
case
ROSE_RESET_REQUEST
:
case
ROSE_RESET_REQUEST
:
*
dptr
++
=
ROSE_GFI
|
lci1
;
*
dptr
++
=
ROSE_GFI
|
lci1
;
*
dptr
++
=
lci2
;
*
dptr
++
=
lci2
;
*
dptr
++
=
frametype
;
*
dptr
++
=
frametype
;
*
dptr
++
=
ROSE_DTE_ORIGINATED
;
*
dptr
++
=
ROSE_DTE_ORIGINATED
;
*
dptr
++
=
0
;
*
dptr
++
=
0
;
break
;
break
;
case
ROSE_RR
:
case
ROSE_RR
:
case
ROSE_RNR
:
case
ROSE_RNR
:
*
dptr
++
=
ROSE_GFI
|
lci1
;
*
dptr
++
=
ROSE_GFI
|
lci1
;
*
dptr
++
=
lci2
;
*
dptr
++
=
lci2
;
*
dptr
=
frametype
;
*
dptr
=
frametype
;
*
dptr
++
|=
(
rose
->
vr
<<
5
)
&
0xE0
;
*
dptr
++
|=
(
rose
->
vr
<<
5
)
&
0xE0
;
break
;
break
;
case
ROSE_CLEAR_CONFIRMATION
:
case
ROSE_CLEAR_CONFIRMATION
:
case
ROSE_RESET_CONFIRMATION
:
case
ROSE_RESET_CONFIRMATION
:
*
dptr
++
=
ROSE_GFI
|
lci1
;
*
dptr
++
=
ROSE_GFI
|
lci1
;
*
dptr
++
=
lci2
;
*
dptr
++
=
lci2
;
*
dptr
++
=
frametype
;
*
dptr
++
=
frametype
;
break
;
break
;
default:
default:
printk
(
KERN_ERR
"ROSE: rose_write_internal - invalid frametype %02X
\n
"
,
frametype
);
printk
(
KERN_ERR
"ROSE: rose_write_internal - invalid frametype %02X
\n
"
,
frametype
);
kfree_skb
(
skb
);
kfree_skb
(
skb
);
return
;
return
;
}
}
rose_transmit_link
(
skb
,
rose
->
neighbour
);
rose_transmit_link
(
skb
,
rose
->
neighbour
);
...
@@ -216,15 +206,15 @@ int rose_decode(struct sk_buff *skb, int *ns, int *nr, int *q, int *d, int *m)
...
@@ -216,15 +206,15 @@ int rose_decode(struct sk_buff *skb, int *ns, int *nr, int *q, int *d, int *m)
*
ns
=
*
nr
=
*
q
=
*
d
=
*
m
=
0
;
*
ns
=
*
nr
=
*
q
=
*
d
=
*
m
=
0
;
switch
(
frame
[
2
])
{
switch
(
frame
[
2
])
{
case
ROSE_CALL_REQUEST
:
case
ROSE_CALL_REQUEST
:
case
ROSE_CALL_ACCEPTED
:
case
ROSE_CALL_ACCEPTED
:
case
ROSE_CLEAR_REQUEST
:
case
ROSE_CLEAR_REQUEST
:
case
ROSE_CLEAR_CONFIRMATION
:
case
ROSE_CLEAR_CONFIRMATION
:
case
ROSE_RESET_REQUEST
:
case
ROSE_RESET_REQUEST
:
case
ROSE_RESET_CONFIRMATION
:
case
ROSE_RESET_CONFIRMATION
:
return
frame
[
2
];
return
frame
[
2
];
default:
default:
break
;
break
;
}
}
if
((
frame
[
2
]
&
0x1F
)
==
ROSE_RR
||
if
((
frame
[
2
]
&
0x1F
)
==
ROSE_RR
||
...
@@ -253,61 +243,61 @@ static int rose_parse_national(unsigned char *p, struct rose_facilities_struct *
...
@@ -253,61 +243,61 @@ static int rose_parse_national(unsigned char *p, struct rose_facilities_struct *
do
{
do
{
switch
(
*
p
&
0xC0
)
{
switch
(
*
p
&
0xC0
)
{
case
0x00
:
case
0x00
:
p
+=
2
;
p
+=
2
;
n
+=
2
;
n
+=
2
;
len
-=
2
;
len
-=
2
;
break
;
break
;
case
0x40
:
case
0x40
:
if
(
*
p
==
FAC_NATIONAL_RAND
)
if
(
*
p
==
FAC_NATIONAL_RAND
)
facilities
->
rand
=
((
p
[
1
]
<<
8
)
&
0xFF00
)
+
((
p
[
2
]
<<
0
)
&
0x00FF
);
facilities
->
rand
=
((
p
[
1
]
<<
8
)
&
0xFF00
)
+
((
p
[
2
]
<<
0
)
&
0x00FF
);
p
+=
3
;
p
+=
3
;
n
+=
3
;
n
+=
3
;
len
-=
3
;
len
-=
3
;
break
;
break
;
case
0x80
:
case
0x80
:
p
+=
4
;
p
+=
4
;
n
+=
4
;
n
+=
4
;
len
-=
4
;
len
-=
4
;
break
;
break
;
case
0xC0
:
case
0xC0
:
l
=
p
[
1
];
l
=
p
[
1
];
if
(
*
p
==
FAC_NATIONAL_DEST_DIGI
)
{
if
(
*
p
==
FAC_NATIONAL_DEST_DIGI
)
{
if
(
!
fac_national_digis_received
)
{
if
(
!
fac_national_digis_received
)
{
memcpy
(
&
facilities
->
source_digis
[
0
],
p
+
2
,
AX25_ADDR_LEN
);
memcpy
(
&
facilities
->
source_digis
[
0
],
p
+
2
,
AX25_ADDR_LEN
);
facilities
->
source_ndigis
=
1
;
facilities
->
source_ndigis
=
1
;
}
}
}
else
if
(
*
p
==
FAC_NATIONAL_SRC_DIGI
)
{
}
if
(
!
fac_national_digis_received
)
{
else
if
(
*
p
==
FAC_NATIONAL_SRC_DIGI
)
{
memcpy
(
&
facilities
->
dest_digis
[
0
],
p
+
2
,
AX25_ADDR_LEN
);
if
(
!
fac_national_digis_received
)
{
facilities
->
dest_ndigis
=
1
;
memcpy
(
&
facilities
->
dest_digis
[
0
],
p
+
2
,
AX25_ADDR_LEN
);
}
facilities
->
dest_ndigis
=
1
;
}
else
if
(
*
p
==
FAC_NATIONAL_FAIL_CALL
)
{
memcpy
(
&
facilities
->
fail_call
,
p
+
2
,
AX25_ADDR_LEN
);
}
else
if
(
*
p
==
FAC_NATIONAL_FAIL_ADD
)
{
memcpy
(
&
facilities
->
fail_addr
,
p
+
3
,
ROSE_ADDR_LEN
);
}
}
else
if
(
*
p
==
FAC_NATIONAL_DIGIS
)
{
}
fac_national_digis_received
=
1
;
else
if
(
*
p
==
FAC_NATIONAL_FAIL_CALL
)
{
facilities
->
source_ndigis
=
0
;
memcpy
(
&
facilities
->
fail_call
,
p
+
2
,
AX25_ADDR_LEN
);
facilities
->
dest_ndigis
=
0
;
}
for
(
pt
=
p
+
2
,
lg
=
0
;
lg
<
l
;
pt
+=
AX25_ADDR_LEN
,
lg
+=
AX25_ADDR_LEN
)
{
else
if
(
*
p
==
FAC_NATIONAL_FAIL_ADD
)
{
if
(
pt
[
6
]
&
AX25_HBIT
)
memcpy
(
&
facilities
->
fail_addr
,
p
+
3
,
ROSE_ADDR_LEN
);
memcpy
(
&
facilities
->
dest_digis
[
facilities
->
dest_ndigis
++
],
pt
,
AX25_ADDR_LEN
);
}
else
else
if
(
*
p
==
FAC_NATIONAL_DIGIS
)
{
memcpy
(
&
facilities
->
source_digis
[
facilities
->
source_ndigis
++
],
pt
,
AX25_ADDR_LEN
);
fac_national_digis_received
=
1
;
}
facilities
->
source_ndigis
=
0
;
facilities
->
dest_ndigis
=
0
;
for
(
pt
=
p
+
2
,
lg
=
0
;
lg
<
l
;
pt
+=
AX25_ADDR_LEN
,
lg
+=
AX25_ADDR_LEN
)
{
if
(
pt
[
6
]
&
AX25_HBIT
)
memcpy
(
&
facilities
->
dest_digis
[
facilities
->
dest_ndigis
++
],
pt
,
AX25_ADDR_LEN
);
else
memcpy
(
&
facilities
->
source_digis
[
facilities
->
source_ndigis
++
],
pt
,
AX25_ADDR_LEN
);
}
}
p
+=
l
+
2
;
}
n
+=
l
+
2
;
p
+=
l
+
2
;
len
-=
l
+
2
;
n
+=
l
+
2
;
break
;
len
-=
l
+
2
;
break
;
}
}
}
while
(
*
p
!=
0x00
&&
len
>
0
);
}
while
(
*
p
!=
0x00
&&
len
>
0
);
...
@@ -321,49 +311,50 @@ static int rose_parse_ccitt(unsigned char *p, struct rose_facilities_struct *fac
...
@@ -321,49 +311,50 @@ static int rose_parse_ccitt(unsigned char *p, struct rose_facilities_struct *fac
do
{
do
{
switch
(
*
p
&
0xC0
)
{
switch
(
*
p
&
0xC0
)
{
case
0x00
:
case
0x00
:
p
+=
2
;
p
+=
2
;
n
+=
2
;
n
+=
2
;
len
-=
2
;
len
-=
2
;
break
;
break
;
case
0x40
:
case
0x40
:
p
+=
3
;
p
+=
3
;
n
+=
3
;
n
+=
3
;
len
-=
3
;
len
-=
3
;
break
;
break
;
case
0x80
:
case
0x80
:
p
+=
4
;
p
+=
4
;
n
+=
4
;
n
+=
4
;
len
-=
4
;
len
-=
4
;
break
;
break
;
case
0xC0
:
case
0xC0
:
l
=
p
[
1
];
l
=
p
[
1
];
if
(
*
p
==
FAC_CCITT_DEST_NSAP
)
{
if
(
*
p
==
FAC_CCITT_DEST_NSAP
)
{
memcpy
(
&
facilities
->
source_addr
,
p
+
7
,
ROSE_ADDR_LEN
);
memcpy
(
&
facilities
->
source_addr
,
p
+
7
,
ROSE_ADDR_LEN
);
memcpy
(
callsign
,
p
+
12
,
l
-
10
);
memcpy
(
callsign
,
p
+
12
,
l
-
10
);
callsign
[
l
-
10
]
=
'\0'
;
callsign
[
l
-
10
]
=
'\0'
;
facilities
->
source_call
=
*
asc2ax
(
callsign
);
facilities
->
source_call
=
*
asc2ax
(
callsign
);
}
}
if
(
*
p
==
FAC_CCITT_SRC_NSAP
)
{
if
(
*
p
==
FAC_CCITT_SRC_NSAP
)
{
memcpy
(
&
facilities
->
dest_addr
,
p
+
7
,
ROSE_ADDR_LEN
);
memcpy
(
&
facilities
->
dest_addr
,
p
+
7
,
ROSE_ADDR_LEN
);
memcpy
(
callsign
,
p
+
12
,
l
-
10
);
memcpy
(
callsign
,
p
+
12
,
l
-
10
);
callsign
[
l
-
10
]
=
'\0'
;
callsign
[
l
-
10
]
=
'\0'
;
facilities
->
dest_call
=
*
asc2ax
(
callsign
);
facilities
->
dest_call
=
*
asc2ax
(
callsign
);
}
}
p
+=
l
+
2
;
p
+=
l
+
2
;
n
+=
l
+
2
;
n
+=
l
+
2
;
len
-=
l
+
2
;
len
-=
l
+
2
;
break
;
break
;
}
}
}
while
(
*
p
!=
0x00
&&
len
>
0
);
}
while
(
*
p
!=
0x00
&&
len
>
0
);
return
n
;
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
;
int
facilities_len
,
len
;
...
@@ -378,26 +369,26 @@ int rose_parse_facilities(unsigned char *p, struct rose_facilities_struct *facil
...
@@ -378,26 +369,26 @@ int rose_parse_facilities(unsigned char *p, struct rose_facilities_struct *facil
p
++
;
p
++
;
switch
(
*
p
)
{
switch
(
*
p
)
{
case
FAC_NATIONAL
:
/* National */
case
FAC_NATIONAL
:
/* National */
len
=
rose_parse_national
(
p
+
1
,
facilities
,
facilities_len
-
1
);
len
=
rose_parse_national
(
p
+
1
,
facilities
,
facilities_len
-
1
);
facilities_len
-=
len
+
1
;
facilities_len
-=
len
+
1
;
p
+=
len
+
1
;
p
+=
len
+
1
;
break
;
break
;
case
FAC_CCITT
:
/* CCITT */
case
FAC_CCITT
:
/* CCITT */
len
=
rose_parse_ccitt
(
p
+
1
,
facilities
,
facilities_len
-
1
);
len
=
rose_parse_ccitt
(
p
+
1
,
facilities
,
facilities_len
-
1
);
facilities_len
-=
len
+
1
;
facilities_len
-=
len
+
1
;
p
+=
len
+
1
;
p
+=
len
+
1
;
break
;
break
;
default:
default:
printk
(
KERN_DEBUG
"ROSE: rose_parse_facilities - unknown facilities family %02X
\n
"
,
*
p
);
printk
(
KERN_DEBUG
"ROSE: rose_parse_facilities - unknown facilities family %02X
\n
"
,
*
p
);
facilities_len
--
;
facilities_len
--
;
p
++
;
p
++
;
break
;
break
;
}
}
}
}
else
else
break
;
/* Error in facilities format */
break
;
/* Error in facilities format */
}
}
return
1
;
return
1
;
...
...
net/rose/rose_timer.c
View file @
b331768e
/*
/*
* 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)
*
* Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org)
* 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.
*/
*/
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
...
@@ -139,34 +131,35 @@ static void rose_heartbeat_expiry(unsigned long param)
...
@@ -139,34 +131,35 @@ static void rose_heartbeat_expiry(unsigned long param)
struct
sock
*
sk
=
(
struct
sock
*
)
param
;
struct
sock
*
sk
=
(
struct
sock
*
)
param
;
rose_cb
*
rose
=
rose_sk
(
sk
);
rose_cb
*
rose
=
rose_sk
(
sk
);
bh_lock_sock
(
sk
);
switch
(
rose
->
state
)
{
switch
(
rose
->
state
)
{
case
ROSE_STATE_0
:
case
ROSE_STATE_0
:
/* Magic here: If we listen() and a new link dies before it
/* Magic here: If we listen() and a new link dies before it
is accepted() it isn't 'dead' so doesn't get removed. */
is accepted() it isn't 'dead' so doesn't get removed. */
if
(
sk
->
destroy
||
(
sk
->
state
==
TCP_LISTEN
&&
sk
->
dead
))
{
if
(
sk
->
destroy
||
(
sk
->
state
==
TCP_LISTEN
&&
sk
->
dead
))
{
rose_destroy_socket
(
sk
);
rose_destroy_socket
(
sk
);
return
;
return
;
}
}
break
;
break
;
case
ROSE_STATE_3
:
case
ROSE_STATE_3
:
/*
/*
* Check for the state of the receive buffer.
* Check for the state of the receive buffer.
*/
*/
if
(
atomic_read
(
&
sk
->
rmem_alloc
)
<
(
sk
->
rcvbuf
/
2
)
&&
if
(
atomic_read
(
&
sk
->
rmem_alloc
)
<
(
sk
->
rcvbuf
/
2
)
&&
(
rose
->
condition
&
ROSE_COND_OWN_RX_BUSY
))
{
(
rose
->
condition
&
ROSE_COND_OWN_RX_BUSY
))
{
rose
->
condition
&=
~
ROSE_COND_OWN_RX_BUSY
;
rose
->
condition
&=
~
ROSE_COND_OWN_RX_BUSY
;
rose
->
condition
&=
~
ROSE_COND_ACK_PENDING
;
rose
->
condition
&=
~
ROSE_COND_ACK_PENDING
;
rose
->
vl
=
rose
->
vr
;
rose
->
vl
=
rose
->
vr
;
rose_write_internal
(
sk
,
ROSE_RR
);
rose_write_internal
(
sk
,
ROSE_RR
);
rose_stop_timer
(
sk
);
/* HB */
rose_stop_timer
(
sk
);
/* HB */
break
;
}
break
;
break
;
}
break
;
}
}
rose_start_heartbeat
(
sk
);
rose_start_heartbeat
(
sk
);
bh_unlock_sock
(
sk
);
}
}
static
void
rose_timer_expiry
(
unsigned
long
param
)
static
void
rose_timer_expiry
(
unsigned
long
param
)
...
@@ -174,33 +167,35 @@ static void rose_timer_expiry(unsigned long param)
...
@@ -174,33 +167,35 @@ static void rose_timer_expiry(unsigned long param)
struct
sock
*
sk
=
(
struct
sock
*
)
param
;
struct
sock
*
sk
=
(
struct
sock
*
)
param
;
rose_cb
*
rose
=
rose_sk
(
sk
);
rose_cb
*
rose
=
rose_sk
(
sk
);
bh_lock_sock
(
sk
);
switch
(
rose
->
state
)
{
switch
(
rose
->
state
)
{
case
ROSE_STATE_1
:
/* T1 */
case
ROSE_STATE_1
:
/* T1 */
case
ROSE_STATE_4
:
/* T2 */
case
ROSE_STATE_4
:
/* T2 */
rose_write_internal
(
sk
,
ROSE_CLEAR_REQUEST
);
rose_write_internal
(
sk
,
ROSE_CLEAR_REQUEST
);
rose
->
state
=
ROSE_STATE_2
;
rose
->
state
=
ROSE_STATE_2
;
rose_start_t3timer
(
sk
);
rose_start_t3timer
(
sk
);
break
;
break
;
case
ROSE_STATE_2
:
/* T3 */
case
ROSE_STATE_2
:
/* T3 */
rose
->
neighbour
->
use
--
;
rose
->
neighbour
->
use
--
;
rose_disconnect
(
sk
,
ETIMEDOUT
,
-
1
,
-
1
);
rose_disconnect
(
sk
,
ETIMEDOUT
,
-
1
,
-
1
);
break
;
break
;
case
ROSE_STATE_3
:
/* HB */
case
ROSE_STATE_3
:
/* HB */
if
(
rose
->
condition
&
ROSE_COND_ACK_PENDING
)
{
if
(
rose
->
condition
&
ROSE_COND_ACK_PENDING
)
{
rose
->
condition
&=
~
ROSE_COND_ACK_PENDING
;
rose
->
condition
&=
~
ROSE_COND_ACK_PENDING
;
rose_enquiry_response
(
sk
);
rose_enquiry_response
(
sk
);
}
}
break
;
break
;
}
}
bh_unlock_sock
(
sk
);
}
}
static
void
rose_idletimer_expiry
(
unsigned
long
param
)
static
void
rose_idletimer_expiry
(
unsigned
long
param
)
{
{
struct
sock
*
sk
=
(
struct
sock
*
)
param
;
struct
sock
*
sk
=
(
struct
sock
*
)
param
;
bh_lock_sock
(
sk
);
rose_clear_queues
(
sk
);
rose_clear_queues
(
sk
);
rose_write_internal
(
sk
,
ROSE_CLEAR_REQUEST
);
rose_write_internal
(
sk
,
ROSE_CLEAR_REQUEST
);
...
@@ -210,10 +205,11 @@ static void rose_idletimer_expiry(unsigned long param)
...
@@ -210,10 +205,11 @@ static void rose_idletimer_expiry(unsigned long param)
sk
->
state
=
TCP_CLOSE
;
sk
->
state
=
TCP_CLOSE
;
sk
->
err
=
0
;
sk
->
err
=
0
;
sk
->
shutdown
|=
SEND_SHUTDOWN
;
sk
->
shutdown
|=
SEND_SHUTDOWN
;
if
(
!
sk
->
dead
)
if
(
!
sk
->
dead
)
sk
->
state_change
(
sk
);
sk
->
state_change
(
sk
);
sk
->
dead
=
1
;
sk
->
dead
=
1
;
bh_unlock_sock
(
sk
);
}
}
net/rose/sysctl_net_rose.c
View file @
b331768e
/* -*- 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.
* Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com)
* Added /proc/sys/net/rose directory entry (empty =) ). [MS]
*/
*/
#include <linux/mm.h>
#include <linux/mm.h>
#include <linux/sysctl.h>
#include <linux/sysctl.h>
#include <linux/init.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