Commit f7c8ad70 authored by Ralf Bächle's avatar Ralf Bächle

Implement locking of internal data for NET/ROM and ROSE.

Do socket locking for AX.25
Delete trailing whitespace.
Exchange prehistoric changelogs in headers with GPL + copyright header.
Reformat some of the NET/ROM and ROSE code to 80 columns.
parent e90d44a8
......@@ -207,7 +207,7 @@ extern spinlock_t ax25_list_lock;
extern void ax25_free_cb(ax25_cb *);
extern void ax25_insert_socket(ax25_cb *);
struct sock *ax25_find_listener(ax25_address *, int, struct net_device *, int);
struct sock *ax25_find_socket(ax25_address *, ax25_address *, int);
struct sock *ax25_get_socket(ax25_address *, ax25_address *, int);
extern ax25_cb *ax25_find_cb(ax25_address *, ax25_address *, ax25_digi *, struct net_device *);
extern struct sock *ax25_addr_match(ax25_address *);
extern void ax25_send_to_raw(struct sock *, struct sk_buff *, int);
......
......@@ -9,6 +9,26 @@ af_ax25.c:ax25_connect:
return sock_error(sk); /* Always set at this point */
}
Do the ax25_list_lock, ax25_uid_lock, ax25_route_lock, protocol_list_lock,
ax25_dev_lock, linkfail_lockreally, ax25_frag_lock and listen_lock have to
be interrupt safe?
Do the ax25_list_lock, ax25_dev_lock, linkfail_lockreally, ax25_frag_lock and
listen_lock have to be interrupt safe?
A device might be deleted after lookup in the SIOCADDRT ioctl but before it's
being used.
Routes to a device begin taken down might be deleted by ax25_rt_device_down
but added by somebody else before the device has been deleted.
Introduce a clear locking strategy. What I've put there is simply an evil
hack to get the code to survive.
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.
/*
* AX.25 release 038
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* AX.25 006 Alan(GW4PTS) Nearly died of shock - it's working 8-)
* AX.25 007 Alan(GW4PTS) Removed the silliest bugs
* AX.25 008 Alan(GW4PTS) Cleaned up, fixed a few state machine problems, added callbacks
* AX.25 009 Alan(GW4PTS) Emergency patch kit to fix memory corruption
* AX.25 010 Alan(GW4PTS) Added RAW sockets/Digipeat.
* AX.25 011 Alan(GW4PTS) RAW socket and datagram fixes (thanks) - Raw sendto now gets PID right
* datagram sendto uses correct target address.
* AX.25 012 Alan(GW4PTS) Correct incoming connection handling, send DM to failed connects.
* Use skb->data not skb+1. Support sk->priority correctly.
* Correct receive on SOCK_DGRAM.
* AX.25 013 Alan(GW4PTS) Send DM to all unknown frames, missing initialiser fixed
* Leave spare SSID bits set (DAMA etc) - thanks for bug report,
* removed device registration (it's not used or needed). Clean up for
* gcc 2.5.8. PID to AX25_P_
* AX.25 014 Alan(GW4PTS) Cleanup and NET3 merge
* AX.25 015 Alan(GW4PTS) Internal test version.
* AX.25 016 Alan(GW4PTS) Semi Internal version for PI card
* work.
* AX.25 017 Alan(GW4PTS) Fixed some small bugs reported by
* G4KLX
* AX.25 018 Alan(GW4PTS) Fixed a small error in SOCK_DGRAM
* AX.25 019 Alan(GW4PTS) Clean ups for the non INET kernel and device ioctls in AX.25
* AX.25 020 Jonathan(G4KLX) /proc support and other changes.
* AX.25 021 Alan(GW4PTS) Added AX25_T1, AX25_N2, AX25_T3 as requested.
* AX.25 022 Jonathan(G4KLX) More work on the ax25 auto router and /proc improved (again)!
* Alan(GW4PTS) Added TIOCINQ/OUTQ
* AX.25 023 Alan(GW4PTS) Fixed shutdown bug
* AX.25 023 Alan(GW4PTS) Linus changed timers
* AX.25 024 Alan(GW4PTS) Small bug fixes
* AX.25 025 Alan(GW4PTS) More fixes, Linux 1.1.51 compatibility stuff, timers again!
* AX.25 026 Alan(GW4PTS) Small state fix.
* AX.25 027 Alan(GW4PTS) Socket close crash fixes.
* AX.25 028 Alan(GW4PTS) Callsign control including settings per uid.
* Small bug fixes.
* Protocol set by sockets only.
* Small changes to allow for start of NET/ROM layer.
* AX.25 028a Jonathan(G4KLX) Changes to state machine.
* AX.25 028b Jonathan(G4KLX) Extracted ax25 control block
* from sock structure.
* AX.25 029 Alan(GW4PTS) Combined 028b and some KA9Q code
* Jonathan(G4KLX) and removed all the old Berkeley, added IP mode registration.
* Darryl(G7LED) stuff. Cross-port digipeating. Minor fixes and enhancements.
* Alan(GW4PTS) Missed suser() on axassociate checks
* AX.25 030 Alan(GW4PTS) Added variable length headers.
* Jonathan(G4KLX) Added BPQ Ethernet interface.
* Steven(GW7RRM) Added digi-peating control ioctl.
* Added extended AX.25 support.
* Added AX.25 frame segmentation.
* Darryl(G7LED) Changed connect(), recvfrom(), sendto() sockaddr/addrlen to
* fall inline with bind() and new policy.
* Moved digipeating ctl to new ax25_dev structs.
* Fixed ax25_release(), set TCP_CLOSE, wakeup app
* context, THEN make the sock dead.
* Alan(GW4PTS) Cleaned up for single recvmsg methods.
* Alan(GW4PTS) Fixed not clearing error on connect failure.
* AX.25 031 Jonathan(G4KLX) Added binding to any device.
* Joerg(DL1BKE) Added DAMA support, fixed (?) digipeating, fixed buffer locking
* for "virtual connect" mode... Result: Probably the
* "Most Buggiest Code You've Ever Seen" (TM)
* HaJo(DD8NE) Implementation of a T5 (idle) timer
* Joerg(DL1BKE) Renamed T5 to IDLE and changed behaviour:
* the timer gets reloaded on every received or transmitted
* I frame for IP or NETROM. The idle timer is not active
* on "vanilla AX.25" connections. Furthermore added PACLEN
* to provide AX.25-layer based fragmentation (like WAMPES)
* AX.25 032 Joerg(DL1BKE) Fixed DAMA timeout error.
* ax25_send_frame() limits the number of enqueued
* datagrams per socket.
* AX.25 033 Jonathan(G4KLX) Removed auto-router.
* Hans(PE1AYX) Converted to Module.
* Joerg(DL1BKE) Moved BPQ Ethernet to separate driver.
* AX.25 034 Jonathan(G4KLX) 2.1 changes
* Alan(GW4PTS) Small POSIXisations
* AX.25 035 Alan(GW4PTS) Started fixing to the new
* format.
* Hans(PE1AYX) Fixed interface to IP layer.
* Alan(GW4PTS) Added asynchronous support.
* Frederic(F1OAT) Support for pseudo-digipeating.
* Jonathan(G4KLX) Support for packet forwarding.
* AX.25 036 Jonathan(G4KLX) Major restructuring.
* Joerg(DL1BKE) Fixed DAMA Slave.
* Jonathan(G4KLX) Fix wildcard listen parameter setting.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* AX.25 038 Matthias(DG2FEF) Small fixes to the syscall interface to make kernel
* independent of AX25_MAX_DIGIS used by applications.
* Tomi(OH2BNS) Fixed ax25_getname().
* Joerg(DL1BKE) Starting to phase out the support for full_sockaddr_ax25
* with only 6 digipeaters and sockaddr_ax25 in ax25_bind(),
* ax25_connect() and ax25_sendmsg()
* Joerg(DL1BKE) Added support for SO_BINDTODEVICE
* Arnaldo C. Melo s/suser/capable(CAP_NET_ADMIN)/, some more cleanups
* Michal Ostrowski Module initialization cleanup.
* Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Darryl Miles G7LED (dlm@g7led.demon.co.uk)
* Copyright (C) Steven Whitehouse GW7RRM (stevew@acm.org)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
* Copyright (C) Hans Alblas PE1AYX (hans@esrac.ele.tue.nl)
* Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
......@@ -177,7 +86,6 @@ static void ax25_remove_socket(ax25_cb *ax25)
unsigned long flags;
spin_lock_irqsave(&ax25_list_lock, flags);
if ((s = ax25_list) == ax25) {
ax25_list = s->next;
spin_unlock_irqrestore(&ax25_list_lock, flags);
......@@ -193,7 +101,6 @@ static void ax25_remove_socket(ax25_cb *ax25)
s = s->next;
}
spin_unlock_irqrestore(&ax25_list_lock, flags);
}
......@@ -222,7 +129,7 @@ static void ax25_kill_by_device(struct net_device *dev)
/*
* Handle device status changes.
*/
static int ax25_device_event(struct notifier_block *this,unsigned long event,
static int ax25_device_event(struct notifier_block *this, unsigned long event,
void *ptr)
{
struct net_device *dev = (struct net_device *)ptr;
......@@ -291,20 +198,23 @@ struct sock *ax25_find_listener(ax25_address *addr, int digi,
/*
* Find an AX.25 socket given both ends.
*/
struct sock *ax25_find_socket(ax25_address *my_addr, ax25_address *dest_addr,
struct sock *ax25_get_socket(ax25_address *my_addr, ax25_address *dest_addr,
int type)
{
ax25_cb *s;
struct sock *sk = NULL;
unsigned long flags;
ax25_cb *s;
spin_lock_irqsave(&ax25_list_lock, flags);
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) {
spin_unlock_irqrestore(&ax25_list_lock, flags);
return s->sk;
sk = s->sk;
lock_sock(sk);
break;
}
}
out:
spin_unlock_irqrestore(&ax25_list_lock, flags);
return NULL;
......@@ -352,18 +262,21 @@ ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr,
struct sock *ax25_addr_match(ax25_address *addr)
{
unsigned long flags;
struct sock *sk = NULL;
ax25_cb *s;
spin_lock_irqsave(&ax25_list_lock, flags);
for (s = ax25_list; s != NULL; s = s->next) {
if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && s->sk->type == SOCK_RAW) {
spin_unlock_irqrestore(&ax25_list_lock, flags);
return s->sk;
if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 &&
s->sk->type == SOCK_RAW) {
sk = s->sk;
lock_sock(sk);
break;
}
}
spin_unlock_irqrestore(&ax25_list_lock, flags);
return NULL;
return sk;
}
void ax25_send_to_raw(struct sock *sk, struct sk_buff *skb, int proto)
......@@ -409,7 +322,7 @@ void ax25_destroy_socket(ax25_cb *ax25)
struct sk_buff *skb;
unsigned long flags;
save_flags(flags); cli();
ax25_remove_socket(ax25);
ax25_stop_heartbeat(ax25);
ax25_stop_t1timer(ax25);
......@@ -417,15 +330,17 @@ void ax25_destroy_socket(ax25_cb *ax25)
ax25_stop_t3timer(ax25);
ax25_stop_idletimer(ax25);
ax25_remove_socket(ax25);
ax25_clear_queues(ax25); /* Flush the queues */
if (ax25->sk != NULL) {
while ((skb = skb_dequeue(&ax25->sk->receive_queue)) != NULL) {
if (skb->sk != ax25->sk) { /* A pending connection */
if (skb->sk != ax25->sk) {
/* A pending connection */
ax25_cb *sax25 = ax25_sk(skb->sk);
skb->sk->dead = 1; /* Queue the unaccepted socket for death */
/* Queue the unaccepted socket for death */
skb->sk->dead = 1;
ax25_start_heartbeat(sax25);
sax25->state = AX25_STATE_0;
}
......@@ -449,8 +364,6 @@ void ax25_destroy_socket(ax25_cb *ax25)
} else {
ax25_free_cb(ax25);
}
restore_flags(flags);
}
/*
......@@ -648,7 +561,7 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname,
if (get_user(opt, (int *)optval))
return -EFAULT;
lock_kernel();
lock_sock(sk);
ax25 = ax25_sk(sk);
switch (optname) {
......@@ -750,12 +663,12 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname,
break;
}
if (sk->type == SOCK_SEQPACKET &&
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;
......@@ -763,7 +676,7 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname,
default:
res = -ENOPROTOOPT;
}
unlock_kernel();
release_sock(sk);
return res;
}
......@@ -784,14 +697,14 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname,
if (get_user(maxlen, optlen))
return -EFAULT;
if (maxlen < 1)
return -EFAULT;
valptr = (void *) &val;
length = min_t(unsigned int, maxlen, sizeof(int));
lock_kernel();
lock_sock(sk);
ax25 = ax25_sk(sk);
switch (optname) {
......@@ -855,10 +768,10 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname,
break;
default:
unlock_kernel();
release_sock(sk);
return -ENOPROTOOPT;
}
unlock_kernel();
release_sock(sk);
if (put_user(length, optlen))
return -EFAULT;
......@@ -869,17 +782,20 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname,
static int ax25_listen(struct socket *sock, int backlog)
{
struct sock *sk = sock->sk;
int res = 0;
lock_kernel();
lock_sock(sk);
if (sk->type == SOCK_SEQPACKET && sk->state != TCP_LISTEN) {
sk->max_ack_backlog = backlog;
sk->state = TCP_LISTEN;
unlock_kernel();
return 0;
goto out;
}
unlock_kernel();
res = -EOPNOTSUPP;
return -EOPNOTSUPP;
out:
release_sock(sk);
return res;
}
int ax25_create(struct socket *sock, int protocol)
......@@ -1028,12 +944,10 @@ static int ax25_release(struct socket *sock)
struct sock *sk = sock->sk;
ax25_cb *ax25;
lock_kernel();
if (sk == NULL) {
unlock_kernel();
if (sk == NULL)
return 0;
}
lock_sock(sk);
ax25 = ax25_sk(sk);
if (sk->type == SOCK_SEQPACKET) {
......@@ -1054,6 +968,7 @@ static int ax25_release(struct socket *sock)
case AX25_STATE_4:
ax25_clear_queues(ax25);
ax25->n2count = 0;
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
......@@ -1093,9 +1008,9 @@ static int ax25_release(struct socket *sock)
ax25_destroy_socket(ax25);
}
sock->sk = NULL;
sock->sk = NULL;
sk->socket = NULL; /* Not used, but we should do this */
unlock_kernel();
release_sock(sk);
return 0;
}
......@@ -1103,29 +1018,23 @@ static int ax25_release(struct socket *sock)
/*
* 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
* 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.
*/
static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
struct sock *sk = sock->sk;
ax25_cb *ax25 = ax25_sk(sk);
struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr;
ax25_address *call;
ax25_dev *ax25_dev = NULL;
ax25_address *call;
ax25_cb *ax25;
int err = 0;
lock_kernel();
if (sk->zapped == 0) {
unlock_kernel();
return -EINVAL;
}
if (addr_len != sizeof(struct sockaddr_ax25) &&
if (addr_len != sizeof(struct sockaddr_ax25) &&
addr_len != sizeof(struct full_sockaddr_ax25)) {
/* support for old structure may go away some time */
if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
(addr_len > sizeof(struct full_sockaddr_ax25))) {
unlock_kernel();
return -EINVAL;
}
......@@ -1133,17 +1042,22 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
current->comm);
}
if (addr->fsa_ax25.sax25_family != AF_AX25) {
unlock_kernel();
if (addr->fsa_ax25.sax25_family != AF_AX25)
return -EINVAL;
}
call = ax25_findbyuid(current->euid);
if (call == NULL && ax25_uid_policy && !capable(CAP_NET_ADMIN)) {
unlock_kernel();
return -EACCES;
}
lock_sock(sk);
ax25 = ax25_sk(sk);
if (sk->zapped == 0) {
err = -EINVAL;
goto out;
}
if (call == NULL)
ax25->source_addr = addr->fsa_ax25.sax25_call;
else
......@@ -1152,20 +1066,19 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
/*
* User already set interface with SO_BINDTODEVICE
*/
if (ax25->ax25_dev != NULL)
goto done;
if (addr_len > sizeof(struct sockaddr_ax25) && addr->fsa_ax25.sax25_ndigis == 1) {
if (ax25cmp(&addr->fsa_digipeater[0], &null_ax25_address) != 0 &&
(ax25_dev = ax25_addr_ax25dev(&addr->fsa_digipeater[0])) == NULL) {
unlock_kernel();
return -EADDRNOTAVAIL;
err = -EADDRNOTAVAIL;
goto out;
}
} else {
} else {
if ((ax25_dev = ax25_addr_ax25dev(&addr->fsa_ax25.sax25_call)) == NULL) {
unlock_kernel();
return -EADDRNOTAVAIL;
err = -EADDRNOTAVAIL;
goto out;
}
}
......@@ -1175,7 +1088,9 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
done:
ax25_insert_socket(ax25);
sk->zapped = 0;
unlock_kernel();
out:
release_sock(sk);
return 0;
}
......@@ -1190,35 +1105,7 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr,
ax25_cb *ax25 = ax25_sk(sk);
struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr;
ax25_digi *digi = NULL;
int ct = 0, err;
lock_kernel();
/* deal with restarts */
if (sock->state == SS_CONNECTING) {
switch (sk->state) {
case TCP_SYN_SENT: /* still trying */
unlock_kernel();
return -EINPROGRESS;
case TCP_ESTABLISHED: /* connection established */
unlock_kernel();
sock->state = SS_CONNECTED;
return 0;
case TCP_CLOSE: /* connection refused */
unlock_kernel();
sock->state = SS_UNCONNECTED;
return -ECONNREFUSED;
}
}
if (sk->state == TCP_ESTABLISHED && sk->type == SOCK_SEQPACKET) {
unlock_kernel();
return -EISCONN; /* No reconnect on a seqpacket socket */
}
sk->state = TCP_CLOSE;
sock->state = SS_UNCONNECTED;
int ct = 0, err = 0;
/*
* some sanity checks. code further down depends on this
......@@ -1233,7 +1120,6 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr,
/* support for old structure may go away some time */
if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
(addr_len > sizeof(struct full_sockaddr_ax25))) {
unlock_kernel();
return -EINVAL;
}
......@@ -1241,29 +1127,56 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr,
current->comm);
}
if (fsa->fsa_ax25.sax25_family != AF_AX25) {
unlock_kernel();
if (fsa->fsa_ax25.sax25_family != AF_AX25)
return -EINVAL;
lock_sock(sk);
/* deal with restarts */
if (sock->state == SS_CONNECTING) {
switch (sk->state) {
case TCP_SYN_SENT: /* still trying */
err = -EINPROGRESS;
goto out;
case TCP_ESTABLISHED: /* connection established */
sock->state = SS_CONNECTED;
goto out;
case TCP_CLOSE: /* connection refused */
sock->state = SS_UNCONNECTED;
err = -ECONNREFUSED;
goto out;
}
}
if (sk->state == TCP_ESTABLISHED && sk->type == SOCK_SEQPACKET) {
err = -EISCONN; /* No reconnect on a seqpacket socket */
goto out;
}
sk->state = TCP_CLOSE;
sock->state = SS_UNCONNECTED;
if (ax25->digipeat != NULL) {
kfree(ax25->digipeat);
ax25->digipeat = NULL;
}
/*
* Handle digi-peaters to be used.
*/
if (addr_len > sizeof(struct sockaddr_ax25) && fsa->fsa_ax25.sax25_ndigis != 0) {
if (addr_len > sizeof(struct sockaddr_ax25) &&
fsa->fsa_ax25.sax25_ndigis != 0) {
/* Valid number of digipeaters ? */
if (fsa->fsa_ax25.sax25_ndigis < 1 || fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS) {
unlock_kernel();
return -EINVAL;
err = -EINVAL;
goto out;
}
if ((digi = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) {
unlock_kernel();
return -ENOBUFS;
err = -ENOBUFS;
goto out;
}
digi->ndigi = fsa->fsa_ax25.sax25_ndigis;
......@@ -1292,13 +1205,14 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr,
printk(KERN_WARNING "ax25_connect(): %s uses autobind, please contact jreuter@yaina.de\n",
current->comm);
if ((err = ax25_rt_autobind(ax25, &fsa->fsa_ax25.sax25_call)) < 0)
return err;
goto out;
ax25_fillin_cb(ax25, ax25->ax25_dev);
ax25_insert_socket(ax25);
} else {
if (ax25->ax25_dev == NULL) {
unlock_kernel();
return -EHOSTUNREACH;
err = -EHOSTUNREACH;
goto out;
}
}
......@@ -1307,8 +1221,8 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr,
ax25->ax25_dev->dev)) {
if (digi != NULL)
kfree(digi);
unlock_kernel();
return -EADDRINUSE; /* Already such a connection */
err = -EADDRINUSE; /* Already such a connection */
goto out;
}
ax25->dest_addr = fsa->fsa_ax25.sax25_call;
......@@ -1318,8 +1232,7 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr,
if (sk->type != SOCK_SEQPACKET) {
sock->state = SS_CONNECTED;
sk->state = TCP_ESTABLISHED;
unlock_kernel();
return 0;
goto out;
}
/* Move to connecting socket, ax.25 lapb WAIT_UA.. */
......@@ -1350,8 +1263,8 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr,
/* Now the loop */
if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) {
unlock_kernel();
return -EINPROGRESS;
err = -EINPROGRESS;
goto out;
}
if (sk->state == TCP_SYN_SENT) {
......@@ -1360,11 +1273,13 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr,
add_wait_queue(sk->sleep, &wait);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (sk->state != TCP_SYN_SENT)
break;
set_current_state(TASK_INTERRUPTIBLE);
release_sock(sk);
if (!signal_pending(tsk)) {
schedule();
lock_sock(sk);
continue;
}
return -ERESTARTSYS;
......@@ -1376,12 +1291,14 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr,
if (sk->state != TCP_ESTABLISHED) {
/* Not in ABM, not in WAIT_UA -> failed */
sock->state = SS_UNCONNECTED;
unlock_kernel();
return sock_error(sk); /* Always set at this point */
err = sock_error(sk); /* Always set at this point */
goto out;
}
sock->state = SS_CONNECTED;
unlock_kernel();
out:
release_sock(sk);
return 0;
}
......@@ -1457,19 +1374,19 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
static int ax25_getname(struct socket *sock, struct sockaddr *uaddr,
int *uaddr_len, int peer)
{
struct sock *sk;
ax25_cb *ax25;
struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr;
struct sock *sk = sock->sk;
unsigned char ndigi, i;
ax25_cb *ax25;
int err = 0;
lock_kernel();
sk = sock->sk;
lock_sock(sk);
ax25 = ax25_sk(sk);
if (peer != 0) {
if (sk->state != TCP_ESTABLISHED) {
unlock_kernel();
return -ENOTCONN;
err = -ENOTCONN;
goto out;
}
fsa->fsa_ax25.sax25_family = AF_AX25;
......@@ -1495,54 +1412,52 @@ static int ax25_getname(struct socket *sock, struct sockaddr *uaddr,
}
}
*uaddr_len = sizeof (struct full_sockaddr_ax25);
unlock_kernel();
return 0;
out:
release_sock(sk);
return err;
}
static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len,
struct scm_cookie *scm)
{
struct sock *sk = sock->sk;
ax25_cb *ax25;
struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name;
int err;
struct sock *sk = sock->sk;
struct sockaddr_ax25 sax;
struct sk_buff *skb;
ax25_digi dtmp, *dp;
unsigned char *asmptr;
int size;
ax25_digi *dp;
ax25_digi dtmp;
int lv;
int addr_len = msg->msg_namelen;
ax25_cb *ax25;
int lv, size, err, addr_len = msg->msg_namelen;
if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR)) {
return -EINVAL;
}
lock_kernel();
lock_sock(sk);
ax25 = ax25_sk(sk);
if (sk->zapped) {
unlock_kernel();
return -EADDRNOTAVAIL;
err = -EADDRNOTAVAIL;
goto out;
}
if (sk->shutdown & SEND_SHUTDOWN) {
unlock_kernel();
send_sig(SIGPIPE, current, 0);
return -EPIPE;
err = -EPIPE;
goto out;
}
if (ax25->ax25_dev == NULL) {
unlock_kernel();
return -ENETUNREACH;
err = -ENETUNREACH;
goto out;
}
if (usax != NULL) {
if (usax->sax25_family != AF_AX25) {
unlock_kernel();
return -EINVAL;
err = -EINVAL;
goto out;
}
if (addr_len == sizeof(struct sockaddr_ax25)) {
......@@ -1553,8 +1468,8 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len,
/* support for old structure may go away some time */
if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
(addr_len > sizeof(struct full_sockaddr_ax25))) {
unlock_kernel();
return -EINVAL;
err = -EINVAL;
goto out;
}
printk(KERN_WARNING "ax25_sendmsg(): %s uses old (6 digipeater) socket structure.\n",
......@@ -1567,8 +1482,8 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len,
/* Valid number of digipeaters ? */
if (usax->sax25_ndigis < 1 || usax->sax25_ndigis > AX25_MAX_DIGIS) {
unlock_kernel();
return -EINVAL;
err = -EINVAL;
goto out;
}
dtmp.ndigi = usax->sax25_ndigis;
......@@ -1584,8 +1499,8 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len,
sax = *usax;
if (sk->type == SOCK_SEQPACKET && ax25cmp(&ax25->dest_addr, &sax.sax25_call) != 0) {
unlock_kernel();
return -EISCONN;
err = -EISCONN;
goto out;
}
if (usax->sax25_ndigis == 0)
dp = NULL;
......@@ -1597,8 +1512,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len,
* it has become closed (not started closed) and is VC
* we ought to SIGPIPE, EPIPE
*/
if (sk->state != TCP_ESTABLISHED)
return -ENOTCONN;
if (sk->state != TCP_ESTABLISHED) {
err = -ENOTCONN;
goto out;
}
sax.sax25_family = AF_AX25;
sax.sax25_call = ax25->dest_addr;
dp = ax25->digipeat;
......@@ -1612,10 +1529,9 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len,
/* Assume the worst case */
size = len + 3 + ax25_addr_size(dp) + AX25_BPQ_HEADER_LEN;
if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) {
unlock_kernel();
return err;
}
skb = sock_alloc_send_skb(sk, size, msg->msg_flags&MSG_DONTWAIT, &err);
if (skb == NULL)
goto out;
skb_reserve(skb, size - len);
......@@ -1637,71 +1553,73 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len,
/* Connected mode sockets go via the LAPB machine */
if (sk->state != TCP_ESTABLISHED) {
kfree_skb(skb);
unlock_kernel();
return -ENOTCONN;
err = -ENOTCONN;
goto out;
}
/* Shove it onto the queue and kick */
ax25_output(ax25, ax25->paclen, skb);
unlock_kernel();
return len;
} else {
asmptr = skb_push(skb, 1 + ax25_addr_size(dp));
err = len;
goto out;
}
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, "Num digipeaters=%d\n", dp->ndigi);
SOCK_DEBUG(sk, "Building AX.25 Header (dp=%p).\n", dp);
/* Build an AX.25 header */
asmptr += (lv = ax25_addr_build(asmptr, &ax25->source_addr,
&sax.sax25_call, dp,
AX25_COMMAND, AX25_MODULUS));
if (dp != NULL)
SOCK_DEBUG(sk, "Num digipeaters=%d\n", dp->ndigi);
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 */
skb->dev = ax25->ax25_dev->dev;
*asmptr = AX25_UI;
ax25_queue_xmit(skb);
unlock_kernel();
/* 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)
{
struct sock *sk;
int copied;
struct sock *sk = sock->sk;
struct sk_buff *skb;
int er;
lock_kernel();
sk = sock->sk;
int copied;
int err = 0;
lock_sock(sk);
/*
* This works for seqpacket too. The receiver has ordered the
* queue for us! We do one quick check first though
*/
if (sk->type == SOCK_SEQPACKET && sk->state != TCP_ESTABLISHED) {
unlock_kernel();
return -ENOTCONN;
err = -ENOTCONN;
goto out;
}
/* Now we can treat all alike */
if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL) {
unlock_kernel();
return er;
}
skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
flags & MSG_DONTWAIT, &err);
if (skb == NULL)
goto out;
if (!ax25_sk(sk)->pidincl)
skb_pull(skb, 1); /* Remove PID */
......@@ -1712,7 +1630,7 @@ static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size,
if (copied > size) {
copied = size;
msg->msg_flags |= MSG_TRUNC;
}
}
skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
......@@ -1741,9 +1659,12 @@ static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size,
}
skb_free_datagram(sk, skb);
unlock_kernel();
err = copied;
return copied;
out:
release_sock(sk);
return err;
}
static int ax25_shutdown(struct socket *sk, int how)
......@@ -1757,7 +1678,7 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
struct sock *sk = sock->sk;
int res = 0;
lock_kernel();
lock_sock(sk);
switch (cmd) {
case TIOCOUTQ: {
long amount;
......@@ -1839,7 +1760,7 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
res = ax25_ctl_ioctl(cmd, (void *)arg);
break;
case SIOCAX25GETINFO:
case SIOCAX25GETINFO:
case SIOCAX25GETINFOOLD: {
ax25_cb *ax25 = ax25_sk(sk);
struct ax25_info_struct ax25_info;
......@@ -1882,7 +1803,7 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
res = -EINVAL;
break;
}
}
}
res = 0;
break;
}
......@@ -1919,8 +1840,8 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
res = dev_ioctl(cmd, (void *)arg);
break;
}
release_sock(sk);
unlock_kernel();
return res;
}
......@@ -1937,24 +1858,24 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length)
/*
* 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) {
len += sprintf(buffer+len, "%8.8lx %s %s%s ",
(long) ax25,
len += sprintf(buffer+len, "%8.8lx %s %s%s ",
(long) ax25,
ax25->ax25_dev == NULL? "???" : ax25->ax25_dev->dev->name,
ax2asc(&ax25->source_addr),
ax25->iamdigi? "*":"");
len += sprintf(buffer+len, "%s", ax2asc(&ax25->dest_addr));
for (k=0; (ax25->digipeat != NULL) && (k < ax25->digipeat->ndigi); k++) {
len += sprintf(buffer+len, ",%s%s",
ax2asc(&ax25->digipeat->calls[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",
ax25->state,
ax25->vs, ax25->vr, ax25->va,
......
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* AX.25 036 Jonathan(G4KLX) Split from ax25_subr.c.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
......@@ -165,14 +152,14 @@ unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, a
if (flags != NULL) {
*flags = 0;
if (buf[6] & AX25_CBIT)
*flags = AX25_COMMAND;
if (buf[13] & AX25_CBIT)
*flags = AX25_RESPONSE;
}
if (dama != NULL)
if (dama != NULL)
*dama = ~buf[13] & AX25_DAMA_FLAG;
/* Copy to, from */
......@@ -243,7 +230,7 @@ int ax25_addr_build(unsigned char *buf, ax25_address *src, ax25_address *dest, a
if (d == NULL || d->ndigi == 0) {
buf[6] |= AX25_EBIT;
return 2 * AX25_ADDR_LEN;
}
}
buf += AX25_ADDR_LEN;
len += AX25_ADDR_LEN;
......@@ -277,7 +264,7 @@ int ax25_addr_size(ax25_digi *dp)
return AX25_ADDR_LEN * (2 + dp->ndigi);
}
/*
/*
* Reverse Digipeat List. May not pass both parameters as same struct
*/
void ax25_digi_invert(ax25_digi *in, ax25_digi *out)
......
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Other kernels modules in this kit are generally BSD derived. See the copyright headers.
*
*
* History
* AX.25 036 Jonathan(G4KLX) Split from ax25_route.c.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
......
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* AX.25 036 Jonathan(G4KLX) Cloned from ax25_in.c
* Joerg(DL1BKE) Fixed it.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Joerg(DL1BKE) ax25->n2count never got reset
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
......@@ -58,7 +43,7 @@ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
break;
case AX25_SABME:
ax25->modulus = AX25_EMODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
......@@ -88,7 +73,7 @@ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
ax25_dama_on(ax25);
/* 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);
......
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* AX.25 036 Jonathan(G4KLX) Cloned from ax25_out.c and ax25_subr.c.
* Joerg(DL1BKE) Changed ax25_ds_enquiry_response(),
* fixed ax25_dama_on() and ax25_dama_off().
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
......@@ -75,7 +60,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
* DL1BKE-7->DB0PRA-6 DB0ACH <I C S3 R5>
*
* 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).
* Is this a Flexnet bug?
*/
......@@ -136,8 +121,8 @@ void ax25_ds_establish_data_link(ax25_cb *ax25)
/*
* :::FIXME:::
* This is a kludge. Not all drivers recognize kiss commands.
* We need a driver level request to switch duplex mode, that does
* This is a kludge. Not all drivers recognize kiss commands.
* We need a driver level request to switch duplex mode, that does
* either SCC changing, PI config or KISS as required. Currently
* this request isn't reliable.
*/
......@@ -168,7 +153,7 @@ 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
* wrong, especially when connections on the device already existed
* 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
* connections exist.
*/
......
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* AX.25 036 Jonathan(G4KLX) Cloned from ax25_timer.c.
* Joerg(DL1BKE) Added DAMA Slave Timeout timer
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
......@@ -42,7 +34,7 @@ static void ax25_ds_timeout(unsigned long);
/*
* 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
* (aka /proc/sys/net/ax25/{dev}/dama_slave_timeout) is still in
* 1/10th of a second.
......@@ -83,15 +75,15 @@ static void ax25_ds_timeout(unsigned long arg)
ax25_dev *ax25_dev = (struct ax25_dev *) arg;
unsigned long flags;
ax25_cb *ax25;
if (ax25_dev == NULL || !ax25_dev->dama.slave)
return; /* Yikes! */
if (!ax25_dev->dama.slave_timeout || --ax25_dev->dama.slave_timeout) {
ax25_ds_set_timer(ax25_dev);
return;
}
spin_lock_irqsave(&ax25_list_lock, flags);
for (ax25=ax25_list; ax25 != NULL; ax25 = ax25->next) {
if (ax25->ax25_dev != ax25_dev || !(ax25->condition & AX25_COND_DAMA_MODE))
......@@ -101,7 +93,7 @@ static void ax25_ds_timeout(unsigned long arg)
ax25_disconnect(ax25, ETIMEDOUT);
}
spin_unlock_irqrestore(&ax25_list_lock, flags);
ax25_dev_dama_off(ax25_dev);
}
......@@ -123,7 +115,7 @@ void ax25_ds_heartbeat_expiry(ax25_cb *ax25)
* Check the state of the receive buffer.
*/
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_ACK_PENDING;
......@@ -135,7 +127,7 @@ void ax25_ds_heartbeat_expiry(ax25_cb *ax25)
ax25_start_heartbeat(ax25);
}
/* dl1bke 960114: T3 works much like the IDLE timeout, but
* gets reloaded with every frame for this
* connection.
......@@ -173,7 +165,7 @@ void ax25_ds_idletimer_expiry(ax25_cb *ax25)
}
/* 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
* get polled by the Master.
*
......@@ -181,9 +173,9 @@ void ax25_ds_idletimer_expiry(ax25_cb *ax25)
* ax25_enquiry_response().
*/
void ax25_ds_t1_timeout(ax25_cb *ax25)
{
{
switch (ax25->state) {
case AX25_STATE_1:
case AX25_STATE_1:
if (ax25->n2count == ax25->n2) {
if (ax25->modulus == AX25_MODULUS) {
ax25_disconnect(ax25, ETIMEDOUT);
......
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* AX.25 036 Jonathan(G4KLX) Split from ax25_timer.c.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
......
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams.
* AX.25 028b Jonathan(G4KLX) Extracted AX25 control block from
* the sock structure.
* AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names.
* Jonathan(G4KLX) Added IP mode registration.
* AX.25 030 Jonathan(G4KLX) Added AX.25 fragment reception.
* Upgraded state machine for SABME.
* Added arbitrary protocol id support.
* AX.25 031 Joerg(DL1BKE) Added DAMA support
* HaJo(DD8NE) Added Idle Disc Timer T5
* Joerg(DL1BKE) Renamed it to "IDLE" with a slightly
* different behaviour. Fixed defrag
* routine (I hope)
* AX.25 032 Darryl(G7LED) AX.25 segmentation fixed.
* AX.25 033 Jonathan(G4KLX) Remove auto-router.
* Modularisation changes.
* AX.25 035 Hans(PE1AYX) Fixed interface to IP layer.
* AX.25 036 Jonathan(G4KLX) Move DAMA code into own file.
* Joerg(DL1BKE) Fixed DAMA Slave.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Thomas(DL9SAU) Fixed missing initialization of skb->protocol.
* Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
*/
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
......@@ -146,7 +116,7 @@ int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb)
#ifdef CONFIG_INET
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
* content.
*/
......@@ -220,17 +190,12 @@ static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, i
static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
ax25_address *dev_addr, struct packet_type *ptype)
{
struct sock *make;
struct sock *sk;
int type = 0;
ax25_address src, dest, *next_digi = NULL;
int type = 0, mine = 0, dama;
struct sock *make, *sk, *raw;
ax25_digi dp, reverse_dp;
ax25_cb *ax25;
ax25_address src, dest;
ax25_address *next_digi = NULL;
ax25_dev *ax25_dev;
struct sock *raw;
int mine = 0;
int dama;
/*
* Process the AX.25/LAPB frame.
......@@ -275,8 +240,10 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
if ((*skb->data & ~0x10) == AX25_UI && dp.lastrepeat + 1 == dp.ndigi) {
skb->h.raw = skb->data + 2; /* skip control and pid */
if ((raw = ax25_addr_match(&dest)) != NULL)
if ((raw = ax25_addr_match(&dest)) != NULL) {
ax25_send_to_raw(raw, skb, skb->data[1]);
release_sock(raw);
}
if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) {
kfree_skb(skb);
......@@ -308,7 +275,8 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
#endif
case AX25_P_TEXT:
/* Now find a suitable dgram socket */
if ((sk = ax25_find_socket(&dest, &src, SOCK_DGRAM)) != NULL) {
sk = ax25_get_socket(&dest, &src, SOCK_DGRAM);
if (sk != NULL) {
if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) {
kfree_skb(skb);
} else {
......@@ -319,6 +287,7 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
if (sock_queue_rcv_skb(sk, skb) != 0)
kfree_skb(skb);
}
release_sock(sk);
} else {
kfree_skb(skb);
}
......@@ -350,9 +319,10 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
if ((ax25 = ax25_find_cb(&dest, &src, &reverse_dp, dev)) != NULL) {
/*
* Process the frame. If it is queued up internally it returns one otherwise we
* free it immediately. This routine itself wakes the user context layers so we
* do no further work
* Process the frame. If it is queued up internally it
* returns one otherwise we free it immediately. This
* routine itself wakes the user context layers so we do
* no further work
*/
if (ax25_process_rx_frame(ax25, skb, type, dama) == 0)
kfree_skb(skb);
......@@ -364,7 +334,8 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
/* a) received not a SABM(E) */
if ((*skb->data & ~AX25_PF) != AX25_SABM && (*skb->data & ~AX25_PF) != AX25_SABME) {
if ((*skb->data & ~AX25_PF) != AX25_SABM &&
(*skb->data & ~AX25_PF) != AX25_SABME) {
/*
* Never reply to a DM. Also ignore any connects for
* addresses that are not our interfaces and not a socket.
......@@ -384,9 +355,12 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
sk = ax25_find_listener(next_digi, 1, dev, SOCK_SEQPACKET);
if (sk != NULL) {
if (sk->ack_backlog == sk->max_ack_backlog || (make = ax25_make_new(sk, ax25_dev)) == NULL) {
if (mine) ax25_return_dm(dev, &src, &dest, &dp);
if (sk->ack_backlog == sk->max_ack_backlog ||
(make = ax25_make_new(sk, ax25_dev)) == NULL) {
if (mine)
ax25_return_dm(dev, &src, &dest, &dp);
kfree_skb(skb);
return 0;
}
......
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* AX.25 036 Jonathan(G4KLX) Split from af_ax25.c.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
......@@ -168,7 +161,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
skb_pull(ourskb, AX25_HEADER_LEN - 1); /* Keep PID */
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);
goto put;
......
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams.
* AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names.
* Jonathan(G4KLX) Only poll when window is full.
* AX.25 030 Jonathan(G4KLX) Added fragmentation to ax25_output.
* Added support for extended AX.25.
* AX.25 031 Joerg(DL1BKE) Added DAMA support
* Joerg(DL1BKE) Modified fragmenter to fragment vanilla
* AX.25 I-Frames. Added PACLEN parameter.
* Joerg(DL1BKE) Fixed a problem with buffer allocation
* for fragments.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Joerg(DL1BKE) Fixed DAMA Slave mode: will work
* on non-DAMA interfaces like AX25L2V2
* again (this behaviour is _required_).
* Joerg(DL1BKE) ax25_check_iframes_acked() returns a
* value now (for DAMA n2count handling)
* Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
*/
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
......@@ -167,9 +141,9 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
if (skb->sk != NULL)
skb_set_owner_w(skbn, skb->sk);
spin_unlock_irqrestore(&ax25_frag_lock, flags);
len = (paclen > skb->len) ? skb->len : paclen;
if (ka9qfrag == 1) {
......@@ -209,7 +183,7 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
break;
#ifdef CONFIG_AX25_DAMA_SLAVE
/*
/*
* A DAMA slave is _required_ to work as normal AX.25L2V2
* if no DAMA master is available.
*/
......@@ -220,7 +194,7 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
}
}
/*
/*
* 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.
*/
......
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Other kernels modules in this kit are generally BSD derived. See the copyright headers.
*
*
* History
* AX.25 020 Jonathan(G4KLX) First go.
* AX.25 022 Jonathan(G4KLX) Added the actual meat to this - we now have a nice heard list.
* AX.25 025 Alan(GW4PTS) First cut at autobinding by route scan.
* AX.25 028b Jonathan(G4KLX) Extracted AX25 control block from the
* sock structure. Device removal now
* removes the heard structure.
* AX.25 029 Steven(GW7RRM) Added /proc information for uid/callsign mapping.
* Jonathan(G4KLX) Handling of IP mode in the routing list and /proc entry.
* AX.25 030 Jonathan(G4KLX) Added digi-peaters to routing table, and
* ioctls to manipulate them. Added port
* configuration.
* AX.25 031 Jonathan(G4KLX) Added concept of default route.
* Joerg(DL1BKE) ax25_rt_build_path() find digipeater list and device by
* destination call. Needed for IP routing via digipeater
* Jonathan(G4KLX) Added routing for IP datagram packets.
* Joerg(DL1BKE) Changed routing for IP datagram and VC to use a default
* route if available. Does not overwrite default routes
* on route-table overflow anymore.
* Joerg(DL1BKE) Fixed AX.25 routing of IP datagram and VC, new ioctl()
* "SIOCAX25OPTRT" to set IP mode and a 'permanent' flag
* on routes.
* AX.25 033 Jonathan(G4KLX) Remove auto-router.
* Joerg(DL1BKE) Moved BPQ Ethernet driver to separate device.
* AX.25 035 Frederic(F1OAT) Support for pseudo-digipeating.
* Jonathan(G4KLX) Support for packet forwarding.
* Arnaldo C. Melo s/suser/capable/
* Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Steven Whitehouse GW7RRM (stevew@acm.org)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
* Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
*/
#include <linux/errno.h>
#include <linux/types.h>
......@@ -315,7 +286,7 @@ int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
off_t begin = 0;
char *callsign;
int i;
read_lock(&ax25_route_lock);
len += sprintf(buffer, "callsign dev mode digipeaters\n");
......@@ -366,7 +337,7 @@ int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
len = length;
return len;
}
}
/*
* Find AX.25 route
......@@ -426,7 +397,7 @@ static inline void ax25_adjust_path(ax25_address *addr, ax25_digi *digipeat)
digipeat->ndigi = k;
}
/*
* Find which interface to use.
......
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
* Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams.
* AX.25 028b Jonathan(G4KLX) Extracted AX25 control block from
* the sock structure.
* AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names.
* Jonathan(G4KLX) Added IP mode registration.
* AX.25 030 Jonathan(G4KLX) Added AX.25 fragment reception.
* Upgraded state machine for SABME.
* Added arbitrary protocol id support.
* AX.25 031 Joerg(DL1BKE) Added DAMA support
* HaJo(DD8NE) Added Idle Disc Timer T5
* Joerg(DL1BKE) Renamed it to "IDLE" with a slightly
* different behaviour. Fixed defrag
* routine (I hope)
* AX.25 032 Darryl(G7LED) AX.25 segmentation fixed.
* AX.25 033 Jonathan(G4KLX) Remove auto-router.
* Modularisation changes.
* AX.25 035 Hans(PE1AYX) Fixed interface to IP layer.
* AX.25 036 Jonathan(G4KLX) Cloned from ax25_in.c.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Most of this code is based on the SDL diagrams published in the 7th ARRL
* Computer Networking Conference papers. The diagrams have mistakes in them,
* but are mostly correct. Before you modify the code could you read the SDL
* diagrams as the code is not obvious and probably very easy to break.
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
......
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* AX.25 036 Jonathan(G4KLX) Split from ax25_out.c.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
......@@ -80,7 +66,7 @@ void ax25_std_transmit_enquiry(ax25_cb *ax25)
ax25_calculate_t1(ax25);
ax25_start_t1timer(ax25);
}
void ax25_std_enquiry_response(ax25_cb *ax25)
{
if (ax25->condition & AX25_COND_OWN_RX_BUSY)
......
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams.
* AX.25 028b Jonathan(G4KLX) Extracted AX25 control block from the
* sock structure.
* AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names.
* AX.25 031 Joerg(DL1BKE) Added DAMA support
* AX.25 032 Joerg(DL1BKE) Fixed DAMA timeout bug
* AX.25 033 Jonathan(G4KLX) Modularisation functions.
* AX.25 035 Frederic(F1OAT) Support for pseudo-digipeating.
* AX.25 036 Jonathan(G4KLX) Split from ax25_timer.c.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
......@@ -116,7 +103,7 @@ void ax25_std_idletimer_expiry(ax25_cb *ax25)
void ax25_std_t1timer_expiry(ax25_cb *ax25)
{
switch (ax25->state) {
case AX25_STATE_1:
case AX25_STATE_1:
if (ax25->n2count == ax25->n2) {
if (ax25->modulus == AX25_MODULUS) {
ax25_disconnect(ax25, ETIMEDOUT);
......@@ -147,7 +134,7 @@ void ax25_std_t1timer_expiry(ax25_cb *ax25)
}
break;
case AX25_STATE_3:
case AX25_STATE_3:
ax25->n2count = 1;
ax25_std_transmit_enquiry(ax25);
ax25->state = AX25_STATE_4;
......
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names. Removed
* old BSD code.
* AX.25 030 Jonathan(G4KLX) Added support for extended AX.25.
* Added fragmentation support.
* Darryl(G7LED) Added function ax25_requeue_frames() to split
* it up from ax25_frames_acked().
* AX.25 031 Joerg(DL1BKE) DAMA needs KISS Fullduplex ON/OFF.
* Thus we have ax25_kiss_cmd() now... ;-)
* Dave Brown(N2RJT)
* Killed a silly bug in the DAMA code.
* Joerg(DL1BKE) Found the real bug in ax25.h, sri.
* AX.25 032 Joerg(DL1BKE) Added ax25_queue_length to count the number of
* enqueued buffers of a socket..
* AX.25 035 Frederic(F1OAT) Support for pseudo-digipeating.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
......@@ -172,9 +148,9 @@ int ax25_decode(ax25_cb *ax25, struct sk_buff *skb, int *ns, int *nr, int *pf)
return frametype;
}
/*
/*
* 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.
*/
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
skb_reserve(skb, AX25_BPQ_HEADER_LEN + ax25_addr_size(digi));
skb->nh.raw = skb->data;
ax25_digi_invert(digi, &retdigi);
dptr = skb_put(skb, 1);
......
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams.
* AX.25 028b Jonathan(G4KLX) Extracted AX25 control block from the
* sock structure.
* AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names.
* AX.25 031 Joerg(DL1BKE) Added DAMA support
* AX.25 032 Joerg(DL1BKE) Fixed DAMA timeout bug
* AX.25 033 Jonathan(G4KLX) Modularisation functions.
* AX.25 035 Frederic(F1OAT) Support for pseudo-digipeating.
* AX.25 036 Jonathan(G4KLX) Split Standard and DAMA code into separate files.
* Joerg(DL1BKE) Fixed DAMA Slave. We are *required* to start with
* standard AX.25 mode.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Tomi(OH2BNS) Fixed heartbeat expiry (check ax25_dev).
* Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Tomi Manninen OH2BNS (oh2bns@sral.fi)
* Copyright (C) Darryl Miles G7LED (dlm@g7led.demon.co.uk)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
*/
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
......
/*
* AX.25 release 037
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* AX.25 036 Jonathan(G4KLX) Split from af_ax25.c.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
......
/* -*- linux-c -*-
* sysctl_net_ax25.c: sysctl interface to net AX.25 subsystem.
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Begun April 1, 1996, Mike Shaver.
* Added /proc/sys/net/ax25 directory entry (empty =) ). [MS]
* Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com)
*/
#include <linux/config.h>
#include <linux/mm.h>
#include <linux/sysctl.h>
......@@ -132,7 +133,7 @@ void ax25_register_sysctl(void)
ax25_table[n].mode = 0555;
#ifndef CONFIG_AX25_DAMA_SLAVE
/*
/*
* We do not wish to have a representation of this parameter
* in /proc/sys/ when configured *not* to include the
* AX.25 DAMA slave code, do we?
......
/*
* NET/ROM release 007
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* NET/ROM 001 Jonathan(G4KLX) Cloned from the AX25 code.
* NET/ROM 002 Darryl(G7LED) Fixes and address enhancement.
* Jonathan(G4KLX) Complete bind re-think.
* Alan(GW4PTS) Trivial tweaks into new format.
* NET/ROM 003 Jonathan(G4KLX) Added G8BPQ extensions.
* Added NET/ROM routing ioctl.
* Darryl(G7LED) Fix autobinding (on connect).
* Fixed nr_release(), set TCP_CLOSE, wakeup app
* context, THEN make the sock dead.
* Circuit ID check before allocating it on
* a connection.
* Alan(GW4PTS) sendmsg/recvmsg only. Fixed connect clear bug
* inherited from AX.25
* NET/ROM 004 Jonathan(G4KLX) Converted to module.
* NET/ROM 005 Jonathan(G4KLX) Linux 2.1
* Alan(GW4PTS) Started POSIXisms
* NET/ROM 006 Alan(GW4PTS) Brought in line with the ANK changes
* Jonathan(G4KLX) Removed hdrincl.
* NET/ROM 007 Jonathan(G4KLX) New timer architecture.
* Implemented Idle timer.
* Arnaldo C. Melo s/suser/capable/, micro cleanups
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk)
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
......@@ -1264,36 +1239,33 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length)
}
static struct net_proto_family nr_family_ops = {
.family = PF_NETROM,
.create = nr_create,
.family = PF_NETROM,
.create = nr_create,
};
static struct proto_ops SOCKOPS_WRAPPED(nr_proto_ops) = {
.family = PF_NETROM,
.release = nr_release,
.bind = nr_bind,
.connect = nr_connect,
.socketpair = sock_no_socketpair,
.accept = nr_accept,
.getname = nr_getname,
.poll = datagram_poll,
.ioctl = nr_ioctl,
.listen = nr_listen,
.shutdown = sock_no_shutdown,
.setsockopt = nr_setsockopt,
.getsockopt = nr_getsockopt,
.sendmsg = nr_sendmsg,
.recvmsg = nr_recvmsg,
.mmap = sock_no_mmap,
.sendpage = sock_no_sendpage,
static struct proto_ops nr_proto_ops = {
.family = PF_NETROM,
.release = nr_release,
.bind = nr_bind,
.connect = nr_connect,
.socketpair = sock_no_socketpair,
.accept = nr_accept,
.getname = nr_getname,
.poll = datagram_poll,
.ioctl = nr_ioctl,
.listen = nr_listen,
.shutdown = sock_no_shutdown,
.setsockopt = nr_setsockopt,
.getsockopt = nr_getsockopt,
.sendmsg = nr_sendmsg,
.recvmsg = nr_recvmsg,
.mmap = sock_no_mmap,
.sendpage = sock_no_sendpage,
};
#include <linux/smp_lock.h>
SOCKOPS_WRAP(nr_proto, PF_NETROM);
static struct notifier_block nr_dev_notifier = {
.notifier_call =nr_device_event,
.notifier_call = nr_device_event,
};
static struct net_device *dev_nr;
......
/*
* NET/ROM release 007
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* NET/ROM 001 Jonathan(G4KLX) Cloned from loopback.c
* NET/ROM 002 Steve Whitehouse(GW7RRM) fixed the set_mac_address
* NET/ROM 003 Jonathan(G4KLX) Put nr_rebuild_header into line with
* ax25_rebuild_header
* NET/ROM 004 Jonathan(G4KLX) Callsign registration with AX.25.
* NET/ROM 006 Hans(PE1AYX) Fixed interface to IP layer.
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
......@@ -115,7 +103,7 @@ static int nr_rebuild_header(struct sk_buff *skb)
kfree_skb(skb);
len = skbn->len;
if (!nr_route_frame(skbn, NULL)) {
kfree_skb(skbn);
stats->tx_errors++;
......
/*
* NET/ROM release 007
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_in.c
* NET/ROM 003 Jonathan(G4KLX) Added NET/ROM fragment reception.
* Darryl(G7LED) Added missing INFO with NAK case, optimized
* INFOACK handling, removed reconnect on error.
* NET/ROM 006 Jonathan(G4KLX) Hdrincl removal changes.
* NET/ROM 007 Jonathan(G4KLX) New timer architecture.
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
......@@ -77,7 +60,7 @@ static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
kfree_skb(skbo);
}
nr->fraglen = 0;
nr->fraglen = 0;
}
return sock_queue_rcv_skb(sk, skbn);
......
/*
* NET/ROM release 007
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* NET/ROM 007 Tomi(OH2BNS) Created this file.
* Small change in nr_loopback_queue().
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Copyright Tomi Manninen OH2BNS (oh2bns@sral.fi)
*/
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/timer.h>
......
/*
* NET/ROM release 007
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_out.c
* NET/ROM 003 Jonathan(G4KLX) Added NET/ROM fragmentation.
* Darryl(G7LED) Fixed NAK, to give out correct reponse.
* NET/ROM 007 Jonathan(G4KLX) New timer architecture.
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
......@@ -85,7 +76,7 @@ void nr_output(struct sock *sk, struct sk_buff *skb)
nr_kick(sk);
}
/*
/*
* 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.
*/
......@@ -104,7 +95,7 @@ static void nr_send_iframe(struct sock *sk, struct sk_buff *skb)
nr_start_idletimer(sk);
nr_transmit_buffer(sk, skb);
nr_transmit_buffer(sk, skb);
}
void nr_send_nak_frame(struct sock *sk)
......
/*
* NET/ROM release 007
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* NET/ROM 001 Jonathan(G4KLX) First attempt.
* NET/ROM 003 Jonathan(G4KLX) Use SIOCADDRT/SIOCDELRT ioctl values
* for NET/ROM routes.
* Use '*' for a blank mnemonic in /proc/net/nr_nodes.
* Change default quality for new neighbour when same
* as node callsign.
* Alan Cox(GW4PTS) Added the firewall hooks.
* NET/ROM 006 Jonathan(G4KLX) Added the setting of digipeated neighbours.
* Tomi(OH2BNS) Routing quality and link failure changes.
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright Tomi Manninen OH2BNS (oh2bns@sral.fi)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
......@@ -47,12 +34,15 @@
#include <linux/notifier.h>
#include <linux/netfilter.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <net/netrom.h>
static unsigned int nr_neigh_no = 1;
static struct nr_node *nr_node_list;
static spinlock_t nr_node_lock;
static struct nr_neigh *nr_neigh_list;
static spinlock_t nr_neigh_lock;
static void nr_remove_neigh(struct nr_neigh *);
......@@ -124,13 +114,10 @@ static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax2
memcpy(nr_neigh->digipeat, ax25_digi, sizeof(ax25_digi));
}
save_flags(flags);
cli();
spin_lock_irqsave(&nr_neigh_lock, flags);
nr_neigh->next = nr_neigh_list;
nr_neigh_list = nr_neigh;
restore_flags(flags);
spin_unlock_irqrestore(&nr_neigh_lock, flags);
}
if (quality != 0 && ax25cmp(nr, ax25) == 0 && !nr_neigh->locked)
......@@ -150,13 +137,10 @@ static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax2
nr_node->routes[0].obs_count = obs_count;
nr_node->routes[0].neighbour = nr_neigh;
save_flags(flags);
cli();
spin_lock_irqsave(&nr_node_lock, flags);
nr_node->next = nr_node_list;
nr_node_list = nr_node;
restore_flags(flags);
spin_unlock_irqrestore(&nr_node_lock, flags);
nr_neigh->count++;
......@@ -259,12 +243,10 @@ static void nr_remove_node(struct nr_node *nr_node)
struct nr_node *s;
unsigned long flags;
save_flags(flags);
cli();
spin_lock_irqsave(&nr_node_lock, flags);
if ((s = nr_node_list) == nr_node) {
nr_node_list = nr_node->next;
restore_flags(flags);
spin_unlock_irqrestore(&nr_node_lock, flags);
kfree(nr_node);
return;
}
......@@ -272,7 +254,7 @@ static void nr_remove_node(struct nr_node *nr_node)
while (s != NULL && s->next != NULL) {
if (s->next == nr_node) {
s->next = nr_node->next;
restore_flags(flags);
spin_unlock_irqrestore(&nr_node_lock, flags);
kfree(nr_node);
return;
}
......@@ -280,20 +262,18 @@ static void nr_remove_node(struct nr_node *nr_node)
s = s->next;
}
restore_flags(flags);
spin_unlock_irqrestore(&nr_node_lock, flags);
}
static void nr_remove_neigh(struct nr_neigh *nr_neigh)
{
struct nr_neigh *s;
unsigned long flags;
save_flags(flags);
cli();
spin_lock_irqsave(&nr_neigh_lock, flags);
if ((s = nr_neigh_list) == nr_neigh) {
nr_neigh_list = nr_neigh->next;
restore_flags(flags);
spin_unlock_irqrestore(&nr_neigh_lock, flags);
if (nr_neigh->digipeat != NULL)
kfree(nr_neigh->digipeat);
kfree(nr_neigh);
......@@ -303,7 +283,7 @@ static void nr_remove_neigh(struct nr_neigh *nr_neigh)
while (s != NULL && s->next != NULL) {
if (s->next == nr_neigh) {
s->next = nr_neigh->next;
restore_flags(flags);
spin_unlock_irqrestore(&nr_neigh_lock, flags);
if (nr_neigh->digipeat != NULL)
kfree(nr_neigh->digipeat);
kfree(nr_neigh);
......@@ -312,8 +292,7 @@ static void nr_remove_neigh(struct nr_neigh *nr_neigh)
s = s->next;
}
restore_flags(flags);
spin_unlock_irqrestore(&nr_neigh_lock, flags);
}
/*
......@@ -330,13 +309,15 @@ static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct n
if (ax25cmp(callsign, &nr_node->callsign) == 0)
break;
if (nr_node == NULL) return -EINVAL;
if (nr_node == NULL)
return -EINVAL;
for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
if (ax25cmp(neighbour, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
break;
if (nr_neigh == NULL) return -EINVAL;
if (nr_neigh == NULL)
return -EINVAL;
for (i = 0; i < nr_node->count; i++) {
if (nr_node->routes[i].neighbour == nr_neigh) {
......@@ -404,15 +385,12 @@ static int nr_add_neigh(ax25_address *callsign, ax25_digi *ax25_digi, struct net
memcpy(nr_neigh->digipeat, ax25_digi, sizeof(ax25_digi));
}
save_flags(flags);
cli();
spin_lock_irqsave(&nr_neigh_lock, flags);
nr_neigh->next = nr_neigh_list;
nr_neigh_list = nr_neigh;
spin_unlock_irqrestore(&nr_neigh_lock, flags);
restore_flags(flags);
return 0;
return 0;
}
/*
......@@ -753,13 +731,13 @@ int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
int nr_nodes_get_info(char *buffer, char **start, off_t offset, int length)
{
struct nr_node *nr_node;
unsigned long flags;
int len = 0;
off_t pos = 0;
off_t begin = 0;
int i;
cli();
spin_lock_irqsave(&nr_node_lock, flags);
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) {
......@@ -767,7 +745,7 @@ int nr_nodes_get_info(char *buffer, char **start, off_t offset, int length)
ax2asc(&nr_node->callsign),
(nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic,
nr_node->which + 1,
nr_node->count);
nr_node->count);
for (i = 0; i < nr_node->count; i++) {
len += sprintf(buffer + len, " %3d %d %05d",
......@@ -788,8 +766,7 @@ int nr_nodes_get_info(char *buffer, char **start, off_t offset, int length)
if (pos > offset + length)
break;
}
sti();
spin_unlock_irqrestore(&nr_node_lock, flags);
*start = buffer + (offset - begin);
len -= (offset - begin);
......@@ -797,18 +774,18 @@ int nr_nodes_get_info(char *buffer, char **start, off_t offset, int length)
if (len > length) len = length;
return len;
}
}
int nr_neigh_get_info(char *buffer, char **start, off_t offset, int length)
{
struct nr_neigh *nr_neigh;
unsigned long flags;
int len = 0;
off_t pos = 0;
off_t begin = 0;
int i;
cli();
spin_lock_irqsave(&nr_neigh_lock, flags);
len += sprintf(buffer, "addr callsign dev qual lock count failed digipeaters\n");
for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) {
......@@ -839,7 +816,7 @@ int nr_neigh_get_info(char *buffer, char **start, off_t offset, int length)
break;
}
sti();
spin_unlock_irqrestore(&nr_neigh_lock, flags);
*start = buffer + (offset - begin);
len -= (offset - begin);
......@@ -847,7 +824,7 @@ int nr_neigh_get_info(char *buffer, char **start, off_t offset, int length)
if (len > length) len = length;
return len;
}
}
/*
* Free all memory associated with the nodes and routes lists.
......
/*
* NET/ROM release 007
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_subr.c
* NET/ROM 003 Jonathan(G4KLX) Added G8BPQ NET/ROM extensions.
* NET/ROM 007 Jonathan(G4KLX) New timer architecture.
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
......@@ -125,7 +116,7 @@ int nr_in_rx_window(struct sock *sk, unsigned short ns)
return 0;
}
/*
/*
* This routine is called when the HDLC layer internally generates a
* control frame.
*/
......@@ -161,7 +152,7 @@ void nr_write_internal(struct sock *sk, int frametype)
* Space for AX.25 and NET/ROM network header
*/
skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN);
dptr = skb_put(skb, skb_tailroom(skb));
switch (frametype & 0x0F) {
......@@ -243,7 +234,7 @@ void nr_transmit_refusal(struct sk_buff *skb, int mine)
dptr[6] &= ~AX25_EBIT;
dptr[6] |= AX25_SSSID_SPARE;
dptr += AX25_ADDR_LEN;
memcpy(dptr, skb->data + 0, AX25_ADDR_LEN);
dptr[6] &= ~AX25_CBIT;
dptr[6] |= AX25_EBIT;
......
/*
* NET/ROM release 007
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_timer.c
* NET/ROM 007 Jonathan(G4KLX) New timer architecture.
* Implemented idle timer.
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
......@@ -223,7 +214,7 @@ static void nr_t1timer_expiry(unsigned long param)
switch (nr->state) {
case NR_STATE_1:
case NR_STATE_1:
if (nr->n2count == nr->n2) {
nr_disconnect(sk, ETIMEDOUT);
return;
......
/* -*- linux-c -*-
* sysctl_net_netrom.c: sysctl interface to net NET/ROM subsystem.
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Begun April 1, 1996, Mike Shaver.
* Added /proc/sys/net/netrom directory entry (empty =) ). [MS]
* Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com)
*/
#include <linux/mm.h>
#include <linux/sysctl.h>
#include <linux/init.h>
......
/*
* ROSE release 003
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from af_netrom.c.
* Alan(GW4PTS) Hacked up for newer API stuff
* Terry (VK2KTJ) Added support for variable length
* address masks.
* ROSE 002 Jonathan(G4KLX) Changed hdrincl to qbitincl.
* Added random number facilities entry.
* Variable number of ROSE devices.
* ROSE 003 Jonathan(G4KLX) New timer architecture.
* Implemented idle timer.
* Added use count to neighbour.
* Tomi(OH2BNS) Fixed rose_getname().
* Arnaldo C. Melo s/suser/capable/ + micro cleanups
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright (C) Terry Dawson VK2KTJ (terry@animats.net)
* Copyright (C) Tomi Manninen OH2BNS (oh2bns@sral.fi)
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
......@@ -33,6 +18,7 @@
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/sockios.h>
......@@ -47,7 +33,7 @@
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/fcntl.h>
#include <linux/termios.h> /* For TIOCINQ/OUTQ */
#include <linux/termios.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/notifier.h>
......@@ -71,6 +57,7 @@ int sysctl_rose_maximum_vcs = ROSE_DEFAULT_MAXVC;
int sysctl_rose_window_size = ROSE_DEFAULT_WINDOW_SIZE;
static struct sock *rose_list;
static spinlock_t rose_list_lock = SPIN_LOCK_UNLOCKED;
static struct proto_ops rose_proto_ops;
......@@ -175,25 +162,23 @@ static void rose_remove_socket(struct sock *sk)
struct sock *s;
unsigned long flags;
save_flags(flags); cli();
spin_lock_irqsave(&rose_list_lock, flags);
if ((s = rose_list) == sk) {
rose_list = s->next;
restore_flags(flags);
spin_unlock_irqrestore(&rose_list_lock, flags);
return;
}
while (s != NULL && s->next != NULL) {
if (s->next == sk) {
s->next = sk->next;
restore_flags(flags);
spin_unlock_irqrestore(&rose_list_lock, flags);
return;
}
s = s->next;
}
restore_flags(flags);
spin_unlock_irqrestore(&rose_list_lock, flags);
}
/*
......@@ -202,8 +187,10 @@ static void rose_remove_socket(struct sock *sk)
*/
void rose_kill_by_neigh(struct rose_neigh *neigh)
{
unsigned long flags;
struct sock *s;
spin_lock_irqsave(&rose_list_lock, flags);
for (s = rose_list; s != NULL; s = s->next) {
rose_cb *rose = rose_sk(s);
......@@ -213,6 +200,7 @@ void rose_kill_by_neigh(struct rose_neigh *neigh)
rose->neighbour = NULL;
}
}
spin_unlock_irqrestore(&rose_list_lock, flags);
}
/*
......@@ -220,8 +208,10 @@ void rose_kill_by_neigh(struct rose_neigh *neigh)
*/
static void rose_kill_by_device(struct net_device *dev)
{
unsigned long flags;
struct sock *s;
spin_lock_irqsave(&rose_list_lock, flags);
for (s = rose_list; s != NULL; s = s->next) {
rose_cb *rose = rose_sk(s);
......@@ -231,12 +221,14 @@ static void rose_kill_by_device(struct net_device *dev)
rose->device = NULL;
}
}
spin_unlock_irqrestore(&rose_list_lock, flags);
}
/*
* 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;
......@@ -244,13 +236,13 @@ static int rose_device_event(struct notifier_block *this, unsigned long event, v
return NOTIFY_DONE;
switch (dev->type) {
case ARPHRD_ROSE:
rose_kill_by_device(dev);
break;
case ARPHRD_AX25:
rose_link_device_down(dev);
rose_rt_device_down(dev);
break;
case ARPHRD_ROSE:
rose_kill_by_device(dev);
break;
case ARPHRD_AX25:
rose_link_device_down(dev);
rose_rt_device_down(dev);
break;
}
return NOTIFY_DONE;
......@@ -263,12 +255,10 @@ static void rose_insert_socket(struct sock *sk)
{
unsigned long flags;
save_flags(flags); cli();
spin_lock_irqsave(&rose_list_lock, flags);
sk->next = rose_list;
rose_list = sk;
restore_flags(flags);
spin_unlock_irqrestore(&rose_list_lock, flags);
}
/*
......@@ -280,15 +270,14 @@ static struct sock *rose_find_listener(rose_address *addr, ax25_address *call)
unsigned long flags;
struct sock *s;
save_flags(flags); cli();
spin_lock_irqsave(&rose_list_lock, flags);
for (s = rose_list; s != NULL; s = s->next) {
rose_cb *rose = rose_sk(s);
if (!rosecmp(&rose->source_addr, addr) &&
!ax25cmp(&rose->source_call, call) &&
!rose->source_ndigis && s->state == TCP_LISTEN) {
restore_flags(flags);
spin_unlock_irqrestore(&rose_list_lock, flags);
return s;
}
}
......@@ -299,12 +288,12 @@ static struct sock *rose_find_listener(rose_address *addr, ax25_address *call)
if (!rosecmp(&rose->source_addr, addr) &&
!ax25cmp(&rose->source_call, &null_ax25_address) &&
s->state == TCP_LISTEN) {
restore_flags(flags);
spin_unlock_irqrestore(&rose_list_lock, flags);
return s;
}
}
spin_unlock_irqrestore(&rose_list_lock, flags);
restore_flags(flags);
return NULL;
}
......@@ -313,21 +302,19 @@ static struct sock *rose_find_listener(rose_address *addr, ax25_address *call)
*/
struct sock *rose_find_socket(unsigned int lci, struct rose_neigh *neigh)
{
struct sock *s;
unsigned long flags;
struct sock *s;
save_flags(flags); cli();
spin_lock_irqsave(&rose_list_lock, flags);
for (s = rose_list; s != NULL; s = s->next) {
rose_cb *rose = rose_sk(s);
if (rose->lci == lci && rose->neighbour == neigh) {
restore_flags(flags);
spin_unlock_irqrestore(&rose_list_lock, flags);
return s;
}
}
restore_flags(flags);
spin_unlock_irqrestore(&rose_list_lock, flags);
return NULL;
}
......@@ -366,23 +353,20 @@ static void rose_destroy_timer(unsigned long data)
}
/*
* This is called from user mode and the timers. Thus it protects itself against
* interrupt users but doesn't worry about being called during work.
* Once it is removed from the queue no interrupt or bottom half will
* touch it and we are (fairly 8-) ) safe.
* This is called from user mode and the timers. Thus it protects itself
* against interrupt users but doesn't worry about being called during
* work. Once it is removed from the queue no interrupt or bottom half
* will touch it and we are (fairly 8-) ) safe.
*/
void rose_destroy_socket(struct sock *sk) /* Not static as it's used by the timer */
void rose_destroy_socket(struct sock *sk)
{
struct sk_buff *skb;
unsigned long flags;
save_flags(flags); cli();
rose_remove_socket(sk);
rose_stop_heartbeat(sk);
rose_stop_idletimer(sk);
rose_stop_timer(sk);
rose_remove_socket(sk);
rose_clear_queues(sk); /* Flush the queues */
while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
......@@ -405,8 +389,6 @@ void rose_destroy_socket(struct sock *sk) /* Not static as it's used by the time
} else {
rose_free_sock(sk);
}
restore_flags(flags);
}
/*
......@@ -484,13 +466,13 @@ static int rose_getsockopt(struct socket *sock, int level, int optname,
if (level != SOL_ROSE)
return -ENOPROTOOPT;
if (get_user(len, optlen))
return -EFAULT;
if (len < 0)
return -EINVAL;
switch (optname) {
case ROSE_DEFER:
val = rose->defer;
......@@ -565,7 +547,7 @@ static int rose_create(struct socket *sock, int protocol)
rose = rose_sk(sk);
sock_init_data(sock, sk);
skb_queue_head_init(&rose->ack_queue);
#ifdef M_BIT
skb_queue_head_init(&rose->frag_queue);
......@@ -679,7 +661,7 @@ static int rose_release(struct socket *sock)
break;
}
sock->sk = NULL;
sock->sk = NULL;
sk->socket = NULL; /* Not used, but we should do this. **/
return 0;
......@@ -877,43 +859,55 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
static int rose_accept(struct socket *sock, struct socket *newsock, int flags)
{
struct sock *sk;
struct sock *newsk;
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
struct sk_buff *skb;
struct sock *newsk;
struct sock *sk;
int err = 0;
if ((sk = sock->sk) == NULL)
return -EINVAL;
if (sk->type != SOCK_SEQPACKET)
return -EOPNOTSUPP;
lock_sock(sk);
if (sk->type != SOCK_SEQPACKET) {
err = -EOPNOTSUPP;
goto out;
}
if (sk->state != TCP_LISTEN)
return -EINVAL;
if (sk->state != TCP_LISTEN) {
err = -EINVAL;
goto out;
}
/*
* The write queue this time is holding sockets ready to use
* hooked into the SABM we saved
*/
do {
cli();
if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
if (flags & O_NONBLOCK) {
sti();
return -EWOULDBLOCK;
}
interruptible_sleep_on(sk->sleep);
if (signal_pending(current)) {
sti();
return -ERESTARTSYS;
}
add_wait_queue(sk->sleep, &wait);
for (;;) {
skb = skb_dequeue(&sk->receive_queue);
if (skb)
break;
current->state = TASK_INTERRUPTIBLE;
release_sock(sk);
if (flags & O_NONBLOCK)
return -EWOULDBLOCK;
if (!signal_pending(tsk)) {
schedule();
lock_sock(sk);
continue;
}
} while (skb == NULL);
return -ERESTARTSYS;
}
current->state = TASK_RUNNING;
remove_wait_queue(sk->sleep, &wait);
newsk = skb->sk;
newsk->pair = NULL;
newsk->socket = newsock;
newsk->sleep = &newsock->wait;
sti();
/* Now attach up the new socket */
skb->sk = NULL;
......@@ -921,7 +915,10 @@ static int rose_accept(struct socket *sock, struct socket *newsock, int flags)
sk->ack_backlog--;
newsock->sk = newsk;
return 0;
out:
release_sock(sk);
return err;
}
static int rose_getname(struct socket *sock, struct sockaddr *uaddr,
......@@ -968,7 +965,7 @@ int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct ros
* skb->data points to the rose frame start
*/
memset(&facilities, 0x00, sizeof(struct rose_facilities_struct));
len = (((skb->data[3] >> 4) & 0x0F) + 1) / 2;
len += (((skb->data[3] >> 0) & 0x0F) + 1) / 2;
if (!rose_parse_facilities(skb->data + len + 4, &facilities)) {
......@@ -1035,7 +1032,7 @@ int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct ros
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 sock *sk = sock->sk;
......@@ -1138,7 +1135,7 @@ static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len,
SOCK_DEBUG(sk, "ROSE: Built header.\n");
SOCK_DEBUG(sk, "ROSE: Transmitting buffer\n");
if (sk->state != TCP_ESTABLISHED) {
kfree_skb(skb);
return -ENOTCONN;
......@@ -1151,7 +1148,7 @@ static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len,
struct sk_buff *skbn;
int frontlen;
int lg;
/* Save a copy of the Header */
memcpy(header, skb->data, ROSE_MIN_LEN);
skb_pull(skb, ROSE_MIN_LEN);
......@@ -1180,10 +1177,10 @@ static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len,
if (skb->len > 0)
skbn->data[2] |= M_BIT;
skb_queue_tail(&sk->write_queue, skbn); /* Throw it on the queue */
}
skb->free = 1;
kfree_skb(skb, FREE_WRITE);
} else {
......@@ -1199,7 +1196,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)
{
struct sock *sk = sock->sk;
......@@ -1366,6 +1363,7 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
static int rose_get_info(char *buffer, char **start, off_t offset, int length)
{
unsigned long flags;
struct sock *s;
struct net_device *dev;
const char *devname, *callsign;
......@@ -1373,7 +1371,7 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length)
off_t pos = 0;
off_t begin = 0;
cli();
spin_lock_irqsave(&rose_list_lock, flags);
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");
......@@ -1397,7 +1395,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",
rose2asc(&rose->source_addr),
callsign,
devname,
devname,
rose->lci & 0x0FFF,
(rose->neighbour) ? rose->neighbour->number : 0,
rose->state,
......@@ -1425,48 +1423,44 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length)
if (pos > offset + length)
break;
}
sti();
spin_unlock_irqrestore(&rose_list_lock, flags);
*start = buffer + (offset - begin);
len -= (offset - begin);
if (len > length) len = length;
return(len);
}
return len;
}
static struct net_proto_family rose_family_ops = {
.family = PF_ROSE,
.create = rose_create,
.family = PF_ROSE,
.create = rose_create,
};
static struct proto_ops SOCKOPS_WRAPPED(rose_proto_ops) = {
.family = PF_ROSE,
.release = rose_release,
.bind = rose_bind,
.connect = rose_connect,
.socketpair = sock_no_socketpair,
.accept = rose_accept,
.getname = rose_getname,
.poll = datagram_poll,
.ioctl = rose_ioctl,
.listen = rose_listen,
.shutdown = sock_no_shutdown,
.setsockopt = rose_setsockopt,
.getsockopt = rose_getsockopt,
.sendmsg = rose_sendmsg,
.recvmsg = rose_recvmsg,
.mmap = sock_no_mmap,
.sendpage = sock_no_sendpage,
static struct proto_ops rose_proto_ops = {
.family = PF_ROSE,
.release = rose_release,
.bind = rose_bind,
.connect = rose_connect,
.socketpair = sock_no_socketpair,
.accept = rose_accept,
.getname = rose_getname,
.poll = datagram_poll,
.ioctl = rose_ioctl,
.listen = rose_listen,
.shutdown = sock_no_shutdown,
.setsockopt = rose_setsockopt,
.getsockopt = rose_getsockopt,
.sendmsg = rose_sendmsg,
.recvmsg = rose_recvmsg,
.mmap = sock_no_mmap,
.sendpage = sock_no_sendpage,
};
#include <linux/smp_lock.h>
SOCKOPS_WRAP(rose_proto, PF_ROSE);
static struct notifier_block rose_dev_notifier = {
.notifier_call =rose_device_event,
.notifier_call = rose_device_event,
};
static struct net_device *dev_rose;
......@@ -1562,5 +1556,5 @@ static void __exit rose_exit(void)
kfree(dev_rose);
}
module_exit(rose_exit);
module_exit(rose_exit);
/*
* ROSE release 003
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from nr_dev.c.
* Hans(PE1AYX) Fixed interface to IP layer.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
......@@ -29,7 +21,7 @@
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/in.h>
#include <linux/if_ether.h> /* For the statistics structure. */
#include <linux/if_ether.h>
#include <asm/system.h>
#include <asm/io.h>
......
/*
* ROSE release 003
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from nr_in.c
* ROSE 002 Jonathan(G4KLX) Return cause and diagnostic codes from Clear Requests.
* ROSE 003 Jonathan(G4KLX) New timer architecture.
* Removed M bit processing.
* Most of this code is based on the SDL diagrams published in the 7th ARRL
* Computer Networking Conference papers. The diagrams have mistakes in them,
* but are mostly correct. Before you modify the code could you read the SDL
* diagrams as the code is not obvious and probably very easy to break.
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
......
/*
* ROSE release 003
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from rose_timer.c
* ROSE 003 Jonathan(G4KLX) New timer architecture.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
......
/*
* ROSE release 003
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* ROSE 003 Jonathan(G4KLX) Created this file from nr_loopback.c.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/timer.h>
......
/*
* ROSE release 003
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from nr_out.c
* ROSE 003 Jonathan(G4KLX) New timer architecture.
* Removed M bit processing.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
......@@ -36,7 +27,7 @@
#include <linux/interrupt.h>
#include <net/rose.h>
/*
/*
* 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.
*/
......@@ -52,7 +43,7 @@ static void rose_send_iframe(struct sock *sk, struct sk_buff *skb)
rose_start_idletimer(sk);
rose_transmit_link(skb, rose->neighbour);
rose_transmit_link(skb, rose->neighbour);
}
void rose_kick(struct sock *sk)
......
/*
* ROSE release 003
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from nr_route.c.
* Terry(VK2KTJ) Added support for variable length
* address masks.
* ROSE 002 Jonathan(G4KLX) Uprated through routing of packets.
* Routing loop detection.
* ROSE 003 Jonathan(G4KLX) New timer architecture.
* Added use count to neighbours.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Terry Dawson VK2KTJ (terry@animats.net)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
......@@ -51,8 +39,11 @@
static unsigned int rose_neigh_no = 1;
static struct rose_node *rose_node_list;
static spinlock_t rose_node_list_lock = SPIN_LOCK_UNLOCKED;
static struct rose_neigh *rose_neigh_list;
static spinlock_t rose_neigh_list_lock = SPIN_LOCK_UNLOCKED;
static struct rose_route *rose_route_list;
static spinlock_t rose_route_list_lock = SPIN_LOCK_UNLOCKED;
struct rose_neigh *rose_loopback_neigh;
......@@ -62,27 +53,45 @@ static void rose_remove_neigh(struct rose_neigh *);
* Add a new route to a node, and in the process add the node and the
* neighbour if it is new.
*/
static int rose_add_node(struct rose_route_struct *rose_route, struct net_device *dev)
static int rose_add_node(struct rose_route_struct *rose_route,
struct net_device *dev)
{
struct rose_node *rose_node, *rose_tmpn, *rose_tmpp;
struct rose_neigh *rose_neigh;
unsigned long flags;
int i;
int i, res = 0;
spin_lock_irqsave(&rose_node_list_lock, flags);
spin_lock_irqsave(&rose_neigh_list_lock, flags);
for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
if ((rose_node->mask == rose_route->mask) && (rosecmpm(&rose_route->address, &rose_node->address, rose_route->mask) == 0))
rose_node = rose_node_list;
while (rose_node != NULL) {
if ((rose_node->mask == rose_route->mask) &&
(rosecmpm(&rose_route->address, &rose_node->address,
rose_route->mask) == 0))
break;
rose_node = rose_node->next;
}
if (rose_node != NULL && rose_node->loopback)
return -EINVAL;
if (rose_node != NULL && rose_node->loopback) {
res = -EINVAL;
goto out;
}
for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 && rose_neigh->dev == dev)
rose_neigh = rose_neigh_list;
while (rose_neigh != NULL) {
if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0
&& rose_neigh->dev == dev)
break;
rose_neigh = rose_neigh->next;
}
if (rose_neigh == NULL) {
if ((rose_neigh = kmalloc(sizeof(*rose_neigh), GFP_ATOMIC)) == NULL)
return -ENOMEM;
rose_neigh = kmalloc(sizeof(*rose_neigh), GFP_ATOMIC);
if (rose_neigh == NULL) {
res = -ENOMEM;
goto out;
}
rose_neigh->callsign = rose_route->neighbour;
rose_neigh->digipeat = NULL;
......@@ -103,22 +112,22 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
if (rose_route->ndigis != 0) {
if ((rose_neigh->digipeat = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) {
kfree(rose_neigh);
return -ENOMEM;
res = -ENOMEM;
goto out;
}
rose_neigh->digipeat->ndigi = rose_route->ndigis;
rose_neigh->digipeat->lastrepeat = -1;
for (i = 0; i < rose_route->ndigis; i++) {
rose_neigh->digipeat->calls[i] = rose_route->digipeaters[i];
rose_neigh->digipeat->calls[i] =
rose_route->digipeaters[i];
rose_neigh->digipeat->repeated[i] = 0;
}
}
save_flags(flags); cli();
rose_neigh->next = rose_neigh_list;
rose_neigh_list = rose_neigh;
restore_flags(flags);
}
/*
......@@ -142,8 +151,11 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
}
/* create new node */
if ((rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL)
return -ENOMEM;
rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC);
if (rose_node == NULL) {
res = -ENOMEM;
goto out;
}
rose_node->address = rose_route->address;
rose_node->mask = rose_route->mask;
......@@ -151,8 +163,6 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
rose_node->loopback = 0;
rose_node->neighbour[0] = rose_neigh;
save_flags(flags); cli();
if (rose_tmpn == NULL) {
if (rose_tmpp == NULL) { /* Empty list */
rose_node_list = rose_node;
......@@ -170,12 +180,9 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
rose_node->next = rose_tmpn;
}
}
restore_flags(flags);
rose_neigh->count++;
return 0;
goto out;
}
/* We have space, slot it in */
......@@ -185,20 +192,24 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
rose_neigh->count++;
}
return 0;
out:
spin_unlock_irqrestore(&rose_neigh_list_lock, flags);
spin_unlock_irqrestore(&rose_node_list_lock, flags);
return res;
}
/*
* Caller is holding rose_node_list_lock.
*/
static void rose_remove_node(struct rose_node *rose_node)
{
struct rose_node *s;
unsigned long flags;
save_flags(flags);
cli();
struct rose_node *s;
spin_lock_irqsave(&rose_node_list_lock, flags);
if ((s = rose_node_list) == rose_node) {
rose_node_list = rose_node->next;
restore_flags(flags);
kfree(rose_node);
return;
}
......@@ -206,17 +217,17 @@ static void rose_remove_node(struct rose_node *rose_node)
while (s != NULL && s->next != NULL) {
if (s->next == rose_node) {
s->next = rose_node->next;
restore_flags(flags);
kfree(rose_node);
return;
}
s = s->next;
}
restore_flags(flags);
}
/*
* Caller is holding rose_neigh_list_lock.
*/
static void rose_remove_neigh(struct rose_neigh *rose_neigh)
{
struct rose_neigh *s;
......@@ -227,11 +238,11 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
skb_queue_purge(&rose_neigh->queue);
save_flags(flags); cli();
spin_lock_irqsave(&rose_neigh_list_lock, flags);
if ((s = rose_neigh_list) == rose_neigh) {
rose_neigh_list = rose_neigh->next;
restore_flags(flags);
spin_unlock_irqrestore(&rose_neigh_list_lock, flags);
if (rose_neigh->digipeat != NULL)
kfree(rose_neigh->digipeat);
kfree(rose_neigh);
......@@ -241,7 +252,7 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
while (s != NULL && s->next != NULL) {
if (s->next == rose_neigh) {
s->next = rose_neigh->next;
restore_flags(flags);
spin_unlock_irqrestore(&rose_neigh_list_lock, flags);
if (rose_neigh->digipeat != NULL)
kfree(rose_neigh->digipeat);
kfree(rose_neigh);
......@@ -250,14 +261,15 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
s = s->next;
}
restore_flags(flags);
spin_unlock_irqrestore(&rose_neigh_list_lock, flags);
}
/*
* Caller is holding rose_route_list_lock.
*/
static void rose_remove_route(struct rose_route *rose_route)
{
struct rose_route *s;
unsigned long flags;
if (rose_route->neigh1 != NULL)
rose_route->neigh1->use--;
......@@ -265,11 +277,8 @@ static void rose_remove_route(struct rose_route *rose_route)
if (rose_route->neigh2 != NULL)
rose_route->neigh2->use--;
save_flags(flags); cli();
if ((s = rose_route_list) == rose_route) {
rose_route_list = rose_route->next;
restore_flags(flags);
kfree(rose_route);
return;
}
......@@ -277,40 +286,55 @@ static void rose_remove_route(struct rose_route *rose_route)
while (s != NULL && s->next != NULL) {
if (s->next == rose_route) {
s->next = rose_route->next;
restore_flags(flags);
kfree(rose_route);
return;
}
s = s->next;
}
restore_flags(flags);
}
/*
* "Delete" a node. Strictly speaking remove a route to a node. The node
* is only deleted if no routes are left to it.
*/
static int rose_del_node(struct rose_route_struct *rose_route, struct net_device *dev)
static int rose_del_node(struct rose_route_struct *rose_route,
struct net_device *dev)
{
struct rose_node *rose_node;
struct rose_neigh *rose_neigh;
int i;
unsigned long flags;
int i, err = 0;
for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
if ((rose_node->mask == rose_route->mask) && (rosecmpm(&rose_route->address, &rose_node->address, rose_route->mask) == 0))
break;
spin_lock_irqsave(&rose_node_list_lock, flags);
spin_lock_irqsave(&rose_neigh_list_lock, flags);
if (rose_node == NULL) return -EINVAL;
rose_node = rose_node_list;
while (rose_node != NULL) {
if ((rose_node->mask == rose_route->mask) &&
(rosecmpm(&rose_route->address, &rose_node->address,
rose_route->mask) == 0))
break;
rose_node = rose_node->next;
}
if (rose_node->loopback) return -EINVAL;
if (rose_node == NULL || rose_node->loopback) {
err = -EINVAL;
goto out;
}
for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 && rose_neigh->dev == dev)
rose_neigh = rose_neigh_list;
while (rose_neigh != NULL) {
if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0
&& rose_neigh->dev == dev)
break;
rose_neigh = rose_neigh->next;
}
if (rose_neigh == NULL) return -EINVAL;
if (rose_neigh == NULL) {
err = -EINVAL;
goto out;
}
for (i = 0; i < rose_node->count; i++) {
if (rose_node->neighbour[i] == rose_neigh) {
......@@ -325,20 +349,26 @@ static int rose_del_node(struct rose_route_struct *rose_route, struct net_device
rose_remove_node(rose_node);
} else {
switch (i) {
case 0:
rose_node->neighbour[0] = rose_node->neighbour[1];
case 1:
rose_node->neighbour[1] = rose_node->neighbour[2];
case 2:
break;
case 0:
rose_node->neighbour[0] =
rose_node->neighbour[1];
case 1:
rose_node->neighbour[1] =
rose_node->neighbour[2];
case 2:
break;
}
}
return 0;
goto out;
}
}
err = -EINVAL;
return -EINVAL;
out:
spin_unlock_irqrestore(&rose_neigh_list_lock, flags);
spin_unlock_irqrestore(&rose_node_list_lock, flags);
return err;
}
/*
......@@ -367,10 +397,10 @@ int rose_add_loopback_neigh(void)
init_timer(&rose_loopback_neigh->ftimer);
init_timer(&rose_loopback_neigh->t0timer);
save_flags(flags); cli();
spin_lock_irqsave(&rose_neigh_list_lock, flags);
rose_loopback_neigh->next = rose_neigh_list;
rose_neigh_list = rose_loopback_neigh;
restore_flags(flags);
spin_unlock_irqrestore(&rose_neigh_list_lock, flags);
return 0;
}
......@@ -382,15 +412,26 @@ int rose_add_loopback_node(rose_address *address)
{
struct rose_node *rose_node;
unsigned long flags;
unsigned int err = 0;
spin_lock_irqsave(&rose_node_list_lock, flags);
for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
if ((rose_node->mask == 10) && (rosecmpm(address, &rose_node->address, 10) == 0) && rose_node->loopback)
rose_node = rose_node_list;
while (rose_node != NULL) {
if ((rose_node->mask == 10) &&
(rosecmpm(address, &rose_node->address, 10) == 0) &&
rose_node->loopback)
break;
rose_node = rose_node->next;
}
if (rose_node != NULL) return 0;
if ((rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL)
return -ENOMEM;
if (rose_node != NULL)
goto out;
if ((rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL) {
err = -ENOMEM;
goto out;
}
rose_node->address = *address;
rose_node->mask = 10;
......@@ -399,13 +440,14 @@ int rose_add_loopback_node(rose_address *address)
rose_node->neighbour[0] = rose_loopback_neigh;
/* Insert at the head of list. Address is always mask=10 */
save_flags(flags); cli();
rose_node->next = rose_node_list;
rose_node_list = rose_node;
restore_flags(flags);
rose_loopback_neigh->count++;
out:
spin_unlock_irqrestore(&rose_node_list_lock, flags);
return 0;
}
......@@ -415,16 +457,28 @@ int rose_add_loopback_node(rose_address *address)
void rose_del_loopback_node(rose_address *address)
{
struct rose_node *rose_node;
unsigned long flags;
for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
if ((rose_node->mask == 10) && (rosecmpm(address, &rose_node->address, 10) == 0) && rose_node->loopback)
spin_lock_irqsave(&rose_node_list_lock, flags);
rose_node = rose_node_list;
while (rose_node != NULL) {
if ((rose_node->mask == 10) &&
(rosecmpm(address, &rose_node->address, 10) == 0) &&
rose_node->loopback)
break;
rose_node = rose_node->next;
}
if (rose_node == NULL) return;
if (rose_node == NULL)
goto out;
rose_remove_node(rose_node);
rose_loopback_neigh->count--;
out:
spin_unlock_irqrestore(&rose_node_list_lock, flags);
}
/*
......@@ -432,52 +486,64 @@ void rose_del_loopback_node(rose_address *address)
*/
void rose_rt_device_down(struct net_device *dev)
{
struct rose_neigh *s, *rose_neigh = rose_neigh_list;
struct rose_neigh *s, *rose_neigh;
struct rose_node *t, *rose_node;
unsigned long flags;
int i;
spin_lock_irqsave(&rose_node_list_lock, flags);
spin_lock_irqsave(&rose_neigh_list_lock, flags);
rose_neigh = rose_neigh_list;
while (rose_neigh != NULL) {
s = rose_neigh;
rose_neigh = rose_neigh->next;
if (s->dev == dev) {
rose_node = rose_node_list;
while (rose_node != NULL) {
t = rose_node;
rose_node = rose_node->next;
for (i = 0; i < t->count; i++) {
if (t->neighbour[i] == s) {
t->count--;
switch (i) {
case 0:
t->neighbour[0] = t->neighbour[1];
case 1:
t->neighbour[1] = t->neighbour[2];
case 2:
break;
}
}
}
if (s->dev != dev)
continue;
rose_node = rose_node_list;
if (t->count <= 0)
rose_remove_node(t);
while (rose_node != NULL) {
t = rose_node;
rose_node = rose_node->next;
for (i = 0; i < t->count; i++) {
if (t->neighbour[i] != s)
continue;
t->count--;
switch (i) {
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_irqrestore(&rose_neigh_list_lock, flags);
spin_unlock_irqrestore(&rose_node_list_lock, flags);
}
#if 0 /* Currently unused */
/*
* A device has been removed. Remove its links.
*/
void rose_route_device_down(struct net_device *dev)
{
struct rose_route *s, *rose_route = rose_route_list;
struct rose_route *s, *rose_route;
unsigned long flags;
spin_lock_irqsave(&rose_route_list_lock, flags);
rose_route = rose_route_list;
while (rose_route != NULL) {
s = rose_route;
rose_route = rose_route->next;
......@@ -485,7 +551,9 @@ void rose_route_device_down(struct net_device *dev)
if (s->neigh1->dev == dev || s->neigh2->dev == dev)
rose_remove_route(s);
}
spin_unlock_irqrestore(&rose_route_list_lock, flags);
}
#endif
/*
* Clear all nodes and neighbours out, except for neighbours with
......@@ -494,8 +562,15 @@ void rose_route_device_down(struct net_device *dev)
*/
static int rose_clear_routes(void)
{
struct rose_neigh *s, *rose_neigh = rose_neigh_list;
struct rose_node *t, *rose_node = rose_node_list;
struct rose_neigh *s, *rose_neigh;
struct rose_node *t, *rose_node;
unsigned long flags;
spin_lock_irqsave(&rose_node_list_lock, flags);
spin_lock_irqsave(&rose_neigh_list_lock, flags);
rose_neigh = rose_neigh_list;
rose_node = rose_node_list;
while (rose_node != NULL) {
t = rose_node;
......@@ -514,6 +589,9 @@ static int rose_clear_routes(void)
}
}
spin_unlock_irqrestore(&rose_neigh_list_lock, flags);
spin_unlock_irqrestore(&rose_node_list_lock, flags);
return 0;
}
......@@ -603,18 +681,23 @@ struct rose_route *rose_route_free_lci(unsigned int lci, struct rose_neigh *neig
/*
* Find a neighbour given a ROSE address.
*/
struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, unsigned char *diagnostic)
struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause,
unsigned char *diagnostic)
{
struct rose_neigh *res = NULL;
struct rose_node *node;
unsigned long flags;
int failed = 0;
int i;
spin_lock_irqsave(&rose_node_list_lock, flags);
for (node = rose_node_list; node != NULL; node = node->next) {
if (rosecmpm(addr, &node->address, node->mask) == 0) {
for (i = 0; i < node->count; i++) {
if (!rose_ftimer_running(node->neighbour[i])) {
return node->neighbour[i]; }
else
res = node->neighbour[i];
goto out;
} else
failed = 1;
}
break;
......@@ -629,7 +712,10 @@ struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, unsi
*diagnostic = 0;
}
return NULL;
out:
spin_unlock_irqrestore(&rose_node_list_lock, flags);
return res;
}
/*
......@@ -642,38 +728,36 @@ int rose_rt_ioctl(unsigned int cmd, void *arg)
int err;
switch (cmd) {
case SIOCADDRT:
if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct)))
return -EFAULT;
if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL)
return -EINVAL;
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);
case SIOCADDRT:
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;
if (rose_dev_exists(&rose_route.address)) { /* Can't add routes to ourself */
dev_put(dev);
return err;
return -EINVAL;
}
if (rose_route.mask > 10) /* Mask can't be more than 10 digits */
return -EINVAL;
case SIOCRSCLRRT:
return rose_clear_routes();
err = rose_add_node(&rose_route, dev);
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;
err = rose_del_node(&rose_route, dev);
dev_put(dev);
return err;
case SIOCRSCLRRT:
return rose_clear_routes();
default:
return -EINVAL;
}
return 0;
......@@ -682,6 +766,7 @@ int rose_rt_ioctl(unsigned int cmd, void *arg)
static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
{
struct rose_route *rose_route, *s;
unsigned long flags;
rose_neigh->restarted = 0;
......@@ -690,6 +775,8 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
skb_queue_purge(&rose_neigh->queue);
spin_lock_irqsave(&rose_route_list_lock, flags);
rose_route = rose_route_list;
while (rose_route != NULL) {
......@@ -716,6 +803,7 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
rose_route = rose_route->next;
}
spin_unlock_irqrestore(&rose_route_list_lock, flags);
}
/*
......@@ -726,17 +814,23 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
void rose_link_failed(ax25_cb *ax25, int reason)
{
struct rose_neigh *rose_neigh;
unsigned long flags;
for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
spin_lock_irqsave(&rose_neigh_list_lock, flags);
rose_neigh = rose_neigh_list;
while (rose_neigh != NULL) {
if (rose_neigh->ax25 == ax25)
break;
rose_neigh = rose_neigh->next;
}
if (rose_neigh == NULL) return;
rose_neigh->ax25 = NULL;
if (rose_neigh != NULL) {
rose_neigh->ax25 = NULL;
rose_del_route_by_neigh(rose_neigh);
rose_kill_by_neigh(rose_neigh);
rose_del_route_by_neigh(rose_neigh);
rose_kill_by_neigh(rose_neigh);
}
spin_unlock_irqrestore(&rose_neigh_list_lock, flags);
}
/*
......@@ -770,11 +864,11 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
unsigned char cause, diagnostic;
struct net_device *dev;
unsigned long flags;
int len;
int len, res = 0;
#if 0
if (call_in_firewall(PF_ROSE, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT)
return 0;
return res;
#endif
frametype = skb->data[2];
......@@ -782,13 +876,22 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
src_addr = (rose_address *)(skb->data + 9);
dest_addr = (rose_address *)(skb->data + 4);
for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
if (ax25cmp(&ax25->dest_addr, &rose_neigh->callsign) == 0 && ax25->ax25_dev->dev == rose_neigh->dev)
spin_lock_irqsave(&rose_node_list_lock, flags);
spin_lock_irqsave(&rose_neigh_list_lock, flags);
spin_lock_irqsave(&rose_route_list_lock, flags);
rose_neigh = rose_neigh_list;
while (rose_neigh != NULL) {
if (ax25cmp(&ax25->dest_addr, &rose_neigh->callsign) == 0 &&
ax25->ax25_dev->dev == rose_neigh->dev)
break;
rose_neigh = rose_neigh->next;
}
if (rose_neigh == NULL) {
printk("rose_route : unknown neighbour or device %s\n", ax2asc(&ax25->dest_addr));
return 0;
printk("rose_route : unknown neighbour or device %s\n",
ax2asc(&ax25->dest_addr));
goto out;
}
/*
......@@ -802,7 +905,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
*/
if (lci == 0) {
rose_link_rx_restart(skb, rose_neigh, frametype);
return 0;
goto out;
}
/*
......@@ -828,7 +931,8 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
}
else {
skb->h.raw = skb->data;
return rose_process_rx_frame(sk, skb);
res = rose_process_rx_frame(sk, skb);
goto out;
}
}
......@@ -837,21 +941,23 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
*/
if (frametype == ROSE_CALL_REQUEST)
if ((dev = rose_dev_get(dest_addr)) != NULL) {
int err = rose_rx_call_request(skb, dev, rose_neigh, lci);
res = rose_rx_call_request(skb, dev, rose_neigh, lci);
dev_put(dev);
return err;
goto out;
}
if (!sysctl_rose_routing_control) {
rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 0);
return 0;
goto out;
}
/*
* Route it to the next in line if we have an entry for it.
*/
for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next) {
if (rose_route->lci1 == lci && rose_route->neigh1 == rose_neigh) {
rose_route = rose_route_list;
while (rose_route != NULL) {
if (rose_route->lci1 == lci &&
rose_route->neigh1 == rose_neigh) {
if (frametype == ROSE_CALL_REQUEST) {
/* F6FBB - Remove an existing unused route */
rose_remove_route(rose_route);
......@@ -863,14 +969,16 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
rose_transmit_link(skb, rose_route->neigh2);
if (frametype == ROSE_CLEAR_CONFIRMATION)
rose_remove_route(rose_route);
return 1;
res = 1;
goto out;
} else {
if (frametype == ROSE_CLEAR_CONFIRMATION)
rose_remove_route(rose_route);
return 0;
goto out;
}
}
if (rose_route->lci2 == lci && rose_route->neigh2 == rose_neigh) {
if (rose_route->lci2 == lci &&
rose_route->neigh2 == rose_neigh) {
if (frametype == ROSE_CALL_REQUEST) {
/* F6FBB - Remove an existing unused route */
rose_remove_route(rose_route);
......@@ -882,13 +990,15 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
rose_transmit_link(skb, rose_route->neigh1);
if (frametype == ROSE_CLEAR_CONFIRMATION)
rose_remove_route(rose_route);
return 1;
res = 1;
goto out;
} else {
if (frametype == ROSE_CLEAR_CONFIRMATION)
rose_remove_route(rose_route);
return 0;
goto out;
}
}
rose_route = rose_route->next;
}
/*
......@@ -903,38 +1013,40 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
len += (((skb->data[3] >> 0) & 0x0F) + 1) / 2;
memset(&facilities, 0x00, sizeof(struct rose_facilities_struct));
if (!rose_parse_facilities(skb->data + len + 4, &facilities)) {
rose_transmit_clear_request(rose_neigh, lci, ROSE_INVALID_FACILITY, 76);
return 0;
goto out;
}
/*
* Check for routing loops.
*/
for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next) {
rose_route = rose_route_list;
while (rose_route != NULL) {
if (rose_route->rand == facilities.rand &&
rosecmp(src_addr, &rose_route->src_addr) == 0 &&
ax25cmp(&facilities.dest_call, &rose_route->src_call) == 0 &&
ax25cmp(&facilities.source_call, &rose_route->dest_call) == 0) {
rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 120);
return 0;
goto out;
}
rose_route = rose_route->next;
}
if ((new_neigh = rose_get_neigh(dest_addr, &cause, &diagnostic)) == NULL) {
rose_transmit_clear_request(rose_neigh, lci, cause, diagnostic);
return 0;
goto out;
}
if ((new_lci = rose_new_lci(new_neigh)) == 0) {
rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 71);
return 0;
goto out;
}
if ((rose_route = kmalloc(sizeof(*rose_route), GFP_ATOMIC)) == NULL) {
rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 120);
return 0;
goto out;
}
rose_route->lci1 = lci;
......@@ -950,29 +1062,34 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
rose_route->neigh1->use++;
rose_route->neigh2->use++;
save_flags(flags); cli();
rose_route->next = rose_route_list;
rose_route_list = rose_route;
restore_flags(flags);
skb->data[0] &= 0xF0;
skb->data[0] |= (rose_route->lci2 >> 8) & 0x0F;
skb->data[1] = (rose_route->lci2 >> 0) & 0xFF;
rose_transmit_link(skb, rose_route->neigh2);
res = 1;
return 1;
out:
spin_unlock_irqrestore(&rose_route_list_lock, flags);
spin_unlock_irqrestore(&rose_neigh_list_lock, flags);
spin_unlock_irqrestore(&rose_node_list_lock, flags);
return res;
}
int rose_nodes_get_info(char *buffer, char **start, off_t offset, int length)
{
struct rose_node *rose_node;
unsigned long flags;
int len = 0;
off_t pos = 0;
off_t begin = 0;
int i;
cli();
spin_lock_irqsave(&rose_neigh_list_lock, flags);
len += sprintf(buffer, "address mask n neigh neigh neigh\n");
......@@ -1004,26 +1121,27 @@ int rose_nodes_get_info(char *buffer, char **start, off_t offset, int length)
if (pos > offset + length)
break;
}
sti();
spin_unlock_irqrestore(&rose_neigh_list_lock, flags);
*start = buffer + (offset - begin);
len -= (offset - begin);
if (len > length) len = length;
if (len > length)
len = length;
return len;
}
}
int rose_neigh_get_info(char *buffer, char **start, off_t offset, int length)
{
struct rose_neigh *rose_neigh;
unsigned long flags;
int len = 0;
off_t pos = 0;
off_t begin = 0;
int i;
cli();
spin_lock_irqsave(&rose_neigh_list_lock, flags);
len += sprintf(buffer, "addr callsign dev count use mode restart t0 tf digipeaters\n");
......@@ -1059,24 +1177,26 @@ int rose_neigh_get_info(char *buffer, char **start, off_t offset, int length)
/* } */
}
sti();
spin_unlock_irqrestore(&rose_neigh_list_lock, flags);
*start = buffer + (offset - begin);
len -= (offset - begin);
if (len > length) len = length;
if (len > length)
len = length;
return len;
}
}
int rose_routes_get_info(char *buffer, char **start, off_t offset, int length)
{
struct rose_route *rose_route;
unsigned long flags;
int len = 0;
off_t pos = 0;
off_t begin = 0;
cli();
spin_lock_irqsave(&rose_route_list_lock, flags);
len += sprintf(buffer, "lci address callsign neigh <-> lci address callsign neigh\n");
......@@ -1112,15 +1232,16 @@ int rose_routes_get_info(char *buffer, char **start, off_t offset, int length)
break;
}
sti();
spin_unlock_irqrestore(&rose_route_list_lock, flags);
*start = buffer + (offset - begin);
len -= (offset - begin);
if (len > length) len = length;
if (len > length)
len = length;
return len;
}
}
/*
* Release all memory associated with ROSE routing structures.
......
/*
* ROSE release 003
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from nr_subr.c
* ROSE 002 Jonathan(G4KLX) Centralised disconnect processing.
* ROSE 003 Jonathan(G4KLX) Added use count to neighbours.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
......@@ -103,7 +94,7 @@ int rose_validate_nr(struct sock *sk, unsigned short nr)
return nr == rose->vs;
}
/*
/*
* This routine is called when the packet layer internally generates a
* control frame.
*/
......@@ -138,7 +129,7 @@ void rose_write_internal(struct sock *sk, int frametype)
* Space for AX.25 header and PID.
*/
skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 1);
dptr = skb_put(skb, skb_tailroom(skb));
lci1 = (rose->lci >> 8) & 0x0F;
......
/*
* ROSE release 003
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from nr_timer.c
* ROSE 003 Jonathan(G4KLX) New timer architecture.
* Implemented idle timer.
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
......@@ -210,7 +201,7 @@ static void rose_idletimer_expiry(unsigned long param)
sk->state = TCP_CLOSE;
sk->err = 0;
sk->shutdown |= SEND_SHUTDOWN;
sk->shutdown |= SEND_SHUTDOWN;
if (!sk->dead)
sk->state_change(sk);
......
/* -*- linux-c -*-
* sysctl_net_rose.c: sysctl interface to net ROSE subsystem.
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Begun April 1, 1996, Mike Shaver.
* Added /proc/sys/net/rose directory entry (empty =) ). [MS]
* Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com)
*/
#include <linux/mm.h>
#include <linux/sysctl.h>
#include <linux/init.h>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment