patch-2.0.35 linux/net/netrom/af_netrom.c
Next file: linux/net/netrom/nr_dev.c
Previous file: linux/net/netrom/Makefile
Back to the patch index
Back to the overall index
- Lines: 1430
- Date:
Mon Jul 13 13:47:41 1998
- Orig file:
v2.0.34/linux/net/netrom/af_netrom.c
- Orig date:
Mon Jul 13 13:46:43 1998
diff -u --recursive --new-file v2.0.34/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
@@ -1,8 +1,5 @@
/*
- * NET/ROM release 003
- *
- * This is ALPHA test software. This code may break your machine, randomly fail to work with new
- * releases, misbehave and/or generally screw up. It might even work.
+ * NET/ROM release 006
*
* This code REQUIRES 1.3.0 or higher/ NET3.029
*
@@ -26,10 +23,12 @@
* a connection.
* Alan(GW4PTS) sendmsg/recvmsg only. Fixed connect clear bug
* inherited from AX.25
+ * NET/ROM 004 Jonathan(G4KLX) Converted to module.
*/
-
+
#include <linux/config.h>
-#ifdef CONFIG_NETROM
+#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
+#include <linux/module.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -60,12 +59,53 @@
#include <net/arp.h>
#include <linux/if_arp.h>
-struct nr_parms_struct nr_default;
+int sysctl_netrom_default_path_quality = NR_DEFAULT_QUAL;
+int sysctl_netrom_obsolescence_count_initialiser = NR_DEFAULT_OBS;
+int sysctl_netrom_network_ttl_initialiser = NR_DEFAULT_TTL;
+int sysctl_netrom_transport_timeout = NR_DEFAULT_T1;
+int sysctl_netrom_transport_maximum_tries = NR_DEFAULT_N2;
+int sysctl_netrom_transport_acknowledge_delay = NR_DEFAULT_T2;
+int sysctl_netrom_transport_busy_delay = NR_DEFAULT_T4;
+int sysctl_netrom_transport_requested_window_size = NR_DEFAULT_WINDOW;
+int sysctl_netrom_routing_control = NR_DEFAULT_ROUTING;
+int sysctl_netrom_link_fails_count = NR_DEFAULT_FAILS;
static unsigned short circuit = 0x101;
static struct sock *volatile nr_list = NULL;
+static void nr_free_sock(struct sock *sk)
+{
+ kfree_s(sk->protinfo.nr, sizeof(*sk->protinfo.nr));
+
+ sk_free(sk);
+
+ MOD_DEC_USE_COUNT;
+}
+
+static struct sock *nr_alloc_sock(void)
+{
+ struct sock *sk;
+ nr_cb *nr;
+
+ if ((sk = sk_alloc(GFP_ATOMIC)) == NULL)
+ return NULL;
+
+ if ((nr = (nr_cb *)kmalloc(sizeof(*nr), GFP_ATOMIC)) == NULL) {
+ sk_free(sk);
+ return NULL;
+ }
+
+ MOD_INC_USE_COUNT;
+
+ memset(nr, 0x00, sizeof(*nr));
+
+ sk->protinfo.nr = nr;
+ nr->sk = sk;
+
+ return sk;
+}
+
/*
* Socket removal during an interrupt is now safe.
*/
@@ -73,7 +113,7 @@
{
struct sock *s;
unsigned long flags;
-
+
save_flags(flags);
cli();
@@ -102,15 +142,16 @@
static void nr_kill_by_device(struct device *dev)
{
struct sock *s;
-
+
for (s = nr_list; s != NULL; s = s->next) {
- if (s->nr->device == dev) {
- s->nr->state = NR_STATE_0;
- s->nr->device = NULL;
- s->state = TCP_CLOSE;
- s->err = ENETUNREACH;
+ if (s->protinfo.nr->device == dev) {
+ s->protinfo.nr->state = NR_STATE_0;
+ s->protinfo.nr->device = NULL;
+ s->state = TCP_CLOSE;
+ s->err = ENETUNREACH;
+ s->shutdown |= SEND_SHUTDOWN;
s->state_change(s);
- s->dead = 1;
+ s->dead = 1;
}
}
}
@@ -124,7 +165,7 @@
if (event != NETDEV_DOWN)
return NOTIFY_DONE;
-
+
nr_kill_by_device(dev);
nr_rt_device_down(dev);
@@ -160,7 +201,7 @@
cli();
for (s = nr_list; s != NULL; s = s->next) {
- if (ax25cmp(&s->nr->source_addr, addr) == 0 && s->state == TCP_LISTEN) {
+ if (ax25cmp(&s->protinfo.nr->source_addr, addr) == 0 && s->state == TCP_LISTEN) {
restore_flags(flags);
return s;
}
@@ -182,7 +223,7 @@
cli();
for (s = nr_list; s != NULL; s = s->next) {
- if (s->nr->my_index == index && s->nr->my_id == id) {
+ if (s->protinfo.nr->my_index == index && s->protinfo.nr->my_id == id) {
restore_flags(flags);
return s;
}
@@ -205,7 +246,7 @@
cli();
for (s = nr_list; s != NULL; s = s->next) {
- if (s->nr->your_index == index && s->nr->your_id == id) {
+ if (s->protinfo.nr->your_index == index && s->protinfo.nr->your_id == id) {
restore_flags(flags);
return s;
}
@@ -217,6 +258,28 @@
}
/*
+ * Find next free circuit ID.
+ */
+static unsigned short nr_find_next_circuit(void)
+{
+ unsigned short id = circuit;
+ unsigned char i, j;
+
+ while (1) {
+ i = id / 256;
+ j = id % 256;
+
+ if (i != 0 && j != 0)
+ if (nr_find_socket(i, j) == NULL)
+ break;
+
+ id++;
+ }
+
+ return id;
+}
+
+/*
* Deferred destroy.
*/
void nr_destroy_socket(struct sock *);
@@ -239,34 +302,33 @@
{
struct sk_buff *skb;
unsigned long flags;
-
+
save_flags(flags);
cli();
-
+
del_timer(&sk->timer);
-
+
nr_remove_socket(sk);
nr_clear_queues(sk); /* Flush the queues */
-
+
while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
if (skb->sk != sk) { /* A pending connection */
skb->sk->dead = 1; /* Queue the unaccepted socket for death */
nr_set_timer(skb->sk);
- skb->sk->nr->state = NR_STATE_0;
+ skb->sk->protinfo.nr->state = NR_STATE_0;
}
kfree_skb(skb, FREE_READ);
}
-
- if (sk->wmem_alloc || sk->rmem_alloc) { /* Defer: outstanding buffers */
+
+ if (sk->wmem_alloc != 0 || sk->rmem_alloc != 0) { /* Defer: outstanding buffers */
init_timer(&sk->timer);
sk->timer.expires = jiffies + 10 * HZ;
sk->timer.function = nr_destroy_timer;
sk->timer.data = (unsigned long)sk;
add_timer(&sk->timer);
} else {
- kfree_s(sk->nr, sizeof(*sk->nr));
- sk_free(sk);
+ nr_free_sock(sk);
}
restore_flags(flags);
@@ -276,96 +338,17 @@
* Handling for system calls applied via the various interfaces to a
* NET/ROM socket object.
*/
-
static int nr_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
return -EINVAL;
}
-/*
- * dl1bke 960311: set parameters for existing NET/ROM connections,
- * includes a KILL command to abort any connection.
- * VERY useful for debugging ;-)
- */
-static int nr_ctl_ioctl(const unsigned int cmd, void *arg)
-{
- struct nr_ctl_struct nr_ctl;
- struct sock *sk;
- unsigned long flags;
- int err;
-
- if ((err = verify_area(VERIFY_READ, arg, sizeof(nr_ctl))) != 0)
- return err;
-
- memcpy_fromfs(&nr_ctl, arg, sizeof(nr_ctl));
-
- if ((sk = nr_find_socket(nr_ctl.index, nr_ctl.id)) == NULL)
- return -ENOTCONN;
-
- switch (nr_ctl.cmd) {
- case NETROM_KILL:
- nr_clear_queues(sk);
- nr_write_internal(sk, NR_DISCREQ);
- sk->nr->state = NR_STATE_0;
- sk->state = TCP_CLOSE;
- sk->err = ENETRESET;
- if (!sk->dead)
- sk->state_change(sk);
- sk->dead = 1;
- nr_set_timer(sk);
- break;
-
- case NETROM_T1:
- if (nr_ctl.arg < 1)
- return -EINVAL;
- sk->nr->rtt = (nr_ctl.arg * PR_SLOWHZ) / 2;
- sk->nr->t1 = nr_ctl.arg * PR_SLOWHZ;
- save_flags(flags); cli();
- if (sk->nr->t1timer > sk->nr->t1)
- sk->nr->t1timer = sk->nr->t1;
- restore_flags(flags);
- break;
-
- case NETROM_T2:
- if (nr_ctl.arg < 1)
- return -EINVAL;
- save_flags(flags); cli();
- sk->nr->t2 = nr_ctl.arg * PR_SLOWHZ;
- if (sk->nr->t2timer > sk->nr->t2)
- sk->nr->t2timer = sk->nr->t2;
- restore_flags(flags);
- break;
-
- case NETROM_N2:
- if (nr_ctl.arg < 1 || nr_ctl.arg > 10)
- return -EINVAL;
- sk->nr->n2count = 0;
- sk->nr->n2 = nr_ctl.arg;
- break;
-
- case NETROM_PACLEN:
- if (nr_ctl.arg < 16 || nr_ctl.arg > 65535)
- return -EINVAL;
- if (nr_ctl.arg > 236) /* we probably want this */
- printk(KERN_WARNING "nr_ctl_ioctl: Warning --- huge paclen %d\n", (int)nr_ctl.arg);
- sk->nr->paclen = nr_ctl.arg;
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
static int nr_setsockopt(struct socket *sock, int level, int optname,
char *optval, int optlen)
{
- struct sock *sk;
+ struct sock *sk = (struct sock *)sock->data;
int err, opt;
- sk = (struct sock *)sock->data;
-
if (level == SOL_SOCKET)
return sock_setsockopt(sk, level, optname, optval, optlen);
@@ -379,36 +362,37 @@
return err;
opt = get_fs_long((unsigned long *)optval);
-
+
switch (optname) {
case NETROM_T1:
if (opt < 1)
return -EINVAL;
- sk->nr->rtt = (opt * PR_SLOWHZ) / 2;
+ sk->protinfo.nr->t1 = opt * NR_SLOWHZ;
return 0;
case NETROM_T2:
if (opt < 1)
return -EINVAL;
- sk->nr->t2 = opt * PR_SLOWHZ;
+ sk->protinfo.nr->t2 = opt * NR_SLOWHZ;
return 0;
-
+
case NETROM_N2:
if (opt < 1 || opt > 31)
return -EINVAL;
- sk->nr->n2 = opt;
+ sk->protinfo.nr->n2 = opt;
return 0;
-
- case NETROM_HDRINCL:
- sk->nr->hdrincl = opt ? 1 : 0;
+
+ case NETROM_T4:
+ if (opt < 1)
+ return -EINVAL;
+ sk->protinfo.nr->t4 = opt * NR_SLOWHZ;
return 0;
- case NETROM_PACLEN:
- if (opt < 1 || opt > 65536)
+ case NETROM_IDLE:
+ if (opt < 0)
return -EINVAL;
- sk->nr->paclen = opt;
return 0;
-
+
default:
return -ENOPROTOOPT;
}
@@ -417,37 +401,35 @@
static int nr_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen)
{
- struct sock *sk;
+ struct sock *sk = (struct sock *)sock->data;
int val = 0;
int err;
- sk = (struct sock *)sock->data;
-
if (level == SOL_SOCKET)
return sock_getsockopt(sk, level, optname, optval, optlen);
-
+
if (level != SOL_NETROM)
return -EOPNOTSUPP;
-
+
switch (optname) {
case NETROM_T1:
- val = (sk->nr->t1 * 2) / PR_SLOWHZ;
+ val = sk->protinfo.nr->t1 / NR_SLOWHZ;
break;
-
+
case NETROM_T2:
- val = sk->nr->t2 / PR_SLOWHZ;
+ val = sk->protinfo.nr->t2 / NR_SLOWHZ;
break;
-
+
case NETROM_N2:
- val = sk->nr->n2;
+ val = sk->protinfo.nr->n2;
break;
-
- case NETROM_HDRINCL:
- val = sk->nr->hdrincl;
+
+ case NETROM_T4:
+ val = sk->protinfo.nr->t4 / NR_SLOWHZ;
break;
- case NETROM_PACLEN:
- val = sk->nr->paclen;
+ case NETROM_IDLE:
+ val = 0;
break;
default:
@@ -472,7 +454,7 @@
struct sock *sk = (struct sock *)sock->data;
if (sk->state != TCP_LISTEN) {
- memset(&sk->nr->user_addr, '\0', AX25_ADDR_LEN);
+ memset(&sk->protinfo.nr->user_addr, '\0', AX25_ADDR_LEN);
sk->max_ack_backlog = backlog;
sk->state = TCP_LISTEN;
return 0;
@@ -501,13 +483,10 @@
if (sock->type != SOCK_SEQPACKET || protocol != 0)
return -ESOCKTNOSUPPORT;
- if ((sk = sk_alloc(GFP_ATOMIC)) == NULL)
+ if ((sk = nr_alloc_sock()) == NULL)
return -ENOMEM;
- if ((nr = (nr_cb *)kmalloc(sizeof(*nr), GFP_ATOMIC)) == NULL) {
- sk_free(sk);
- return -ENOMEM;
- }
+ nr = sk->protinfo.nr;
skb_queue_head_init(&sk->receive_queue);
skb_queue_head_init(&sk->write_queue);
@@ -525,7 +504,6 @@
sk->priority = SOPRI_NORMAL;
sk->mtu = NETROM_MTU; /* 236 */
sk->zapped = 1;
- sk->window = nr_default.window;
sk->state_change = def_callback1;
sk->data_ready = def_callback2;
@@ -541,42 +519,14 @@
skb_queue_head_init(&nr->reseq_queue);
skb_queue_head_init(&nr->frag_queue);
- nr->my_index = 0;
- nr->my_id = 0;
- nr->rtt = nr_default.timeout / 2;
- nr->t1 = nr_default.timeout;
- nr->t2 = nr_default.ack_delay;
- nr->n2 = nr_default.tries;
- nr->paclen = nr_default.paclen;
-
- nr->t1timer = 0;
- nr->t2timer = 0;
- nr->t4timer = 0;
- nr->n2count = 0;
-
- nr->va = 0;
- nr->vr = 0;
- nr->vs = 0;
- nr->vl = 0;
-
- nr->your_index = 0;
- nr->your_id = 0;
-
- nr->my_index = 0;
- nr->my_id = 0;
-
- nr->bpqext = 1;
- nr->fraglen = 0;
- nr->hdrincl = 0;
- nr->state = NR_STATE_0;
- nr->device = NULL;
-
- memset(&nr->source_addr, '\0', AX25_ADDR_LEN);
- memset(&nr->user_addr, '\0', AX25_ADDR_LEN);
- memset(&nr->dest_addr, '\0', AX25_ADDR_LEN);
+ nr->t1 = sysctl_netrom_transport_timeout;
+ nr->t2 = sysctl_netrom_transport_acknowledge_delay;
+ nr->n2 = sysctl_netrom_transport_maximum_tries;
+ nr->t4 = sysctl_netrom_transport_busy_delay;
+ nr->window = sysctl_netrom_transport_requested_window_size;
- nr->sk = sk;
- sk->nr = nr;
+ nr->bpqext = 1;
+ nr->state = NR_STATE_0;
return 0;
}
@@ -589,13 +539,10 @@
if (osk->type != SOCK_SEQPACKET)
return NULL;
- if ((sk = (struct sock *)sk_alloc(GFP_ATOMIC)) == NULL)
+ if ((sk = nr_alloc_sock()) == NULL)
return NULL;
- if ((nr = (nr_cb *)kmalloc(sizeof(*nr), GFP_ATOMIC)) == NULL) {
- sk_free(sk);
- return NULL;
- }
+ nr = sk->protinfo.nr;
skb_queue_head_init(&sk->receive_queue);
skb_queue_head_init(&sk->write_queue);
@@ -611,7 +558,6 @@
sk->sndbuf = osk->sndbuf;
sk->debug = osk->debug;
sk->state = TCP_ESTABLISHED;
- sk->window = osk->window;
sk->mtu = osk->mtu;
sk->sleep = osk->sleep;
sk->zapped = osk->zapped;
@@ -625,29 +571,14 @@
skb_queue_head_init(&nr->reseq_queue);
skb_queue_head_init(&nr->frag_queue);
- nr->rtt = osk->nr->rtt;
- nr->t1 = osk->nr->t1;
- nr->t2 = osk->nr->t2;
- nr->n2 = osk->nr->n2;
- nr->paclen = osk->nr->paclen;
-
- nr->device = osk->nr->device;
- nr->bpqext = osk->nr->bpqext;
- nr->hdrincl = osk->nr->hdrincl;
- nr->fraglen = 0;
-
- nr->t1timer = 0;
- nr->t2timer = 0;
- nr->t4timer = 0;
- nr->n2count = 0;
-
- nr->va = 0;
- nr->vr = 0;
- nr->vs = 0;
- nr->vl = 0;
-
- sk->nr = nr;
- nr->sk = sk;
+ nr->t1 = osk->protinfo.nr->t1;
+ nr->t2 = osk->protinfo.nr->t2;
+ nr->n2 = osk->protinfo.nr->n2;
+ nr->t4 = osk->protinfo.nr->t4;
+ nr->window = osk->protinfo.nr->window;
+
+ nr->device = osk->protinfo.nr->device;
+ nr->bpqext = osk->protinfo.nr->bpqext;
return sk;
}
@@ -656,6 +587,9 @@
{
struct sock *sk = (struct sock *)oldsock->data;
+ if (sk == NULL || newsock == NULL)
+ return -EINVAL;
+
return nr_create(newsock, sk->protocol);
}
@@ -665,44 +599,48 @@
if (sk == NULL) return 0;
- switch (sk->nr->state) {
+ switch (sk->protinfo.nr->state) {
case NR_STATE_0:
sk->state = TCP_CLOSE;
+ sk->shutdown |= SEND_SHUTDOWN;
sk->state_change(sk);
sk->dead = 1;
nr_destroy_socket(sk);
break;
- case NR_STATE_1:
- sk->nr->state = NR_STATE_0;
- sk->state = TCP_CLOSE;
- sk->state_change(sk);
- sk->dead = 1;
+ case NR_STATE_1:
+ sk->protinfo.nr->state = NR_STATE_0;
+ sk->state = TCP_CLOSE;
+ sk->shutdown |= SEND_SHUTDOWN;
+ sk->state_change(sk);
+ sk->dead = 1;
nr_destroy_socket(sk);
break;
case NR_STATE_2:
nr_write_internal(sk, NR_DISCACK);
- sk->nr->state = NR_STATE_0;
- sk->state = TCP_CLOSE;
+ sk->protinfo.nr->state = NR_STATE_0;
+ sk->state = TCP_CLOSE;
+ sk->shutdown |= SEND_SHUTDOWN;
sk->state_change(sk);
- sk->dead = 1;
+ sk->dead = 1;
nr_destroy_socket(sk);
break;
case NR_STATE_3:
nr_clear_queues(sk);
- sk->nr->n2count = 0;
+ sk->protinfo.nr->n2count = 0;
nr_write_internal(sk, NR_DISCREQ);
- sk->nr->t1timer = sk->nr->t1 = nr_calculate_t1(sk);
- sk->nr->t2timer = 0;
- sk->nr->t4timer = 0;
- sk->nr->state = NR_STATE_2;
- sk->state = TCP_CLOSE;
+ sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;
+ sk->protinfo.nr->t2timer = 0;
+ sk->protinfo.nr->t4timer = 0;
+ sk->protinfo.nr->state = NR_STATE_2;
+ sk->state = TCP_CLOSE;
+ sk->shutdown |= SEND_SHUTDOWN;
sk->state_change(sk);
- sk->dead = 1;
- sk->destroy = 1;
+ sk->dead = 1;
+ sk->destroy = 1;
break;
default:
@@ -717,19 +655,20 @@
static int nr_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
- struct sock *sk;
+ struct sock *sk = (struct sock *)sock->data;
struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr;
struct device *dev;
ax25_address *user, *source;
-
- sk = (struct sock *)sock->data;
if (sk->zapped == 0)
- return -EIO;
-
+ return -EINVAL;
+
if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25))
return -EINVAL;
+ if (addr->fsa_ax25.sax25_family != AF_NETROM)
+ return -EINVAL;
+
if ((dev = nr_dev_get(&addr->fsa_ax25.sax25_call)) == NULL) {
if (sk->debug)
printk("NET/ROM: bind failed: invalid node callsign\n");
@@ -741,9 +680,9 @@
*/
if (addr->fsa_ax25.sax25_ndigis == 1) {
if (!suser())
- return -EPERM;
- sk->nr->user_addr = addr->fsa_digipeater[0];
- sk->nr->source_addr = addr->fsa_ax25.sax25_call;
+ return -EACCES;
+ sk->protinfo.nr->user_addr = addr->fsa_digipeater[0];
+ sk->protinfo.nr->source_addr = addr->fsa_ax25.sax25_call;
} else {
source = &addr->fsa_ax25.sax25_call;
@@ -753,11 +692,11 @@
user = source;
}
- sk->nr->user_addr = *user;
- sk->nr->source_addr = *source;
+ sk->protinfo.nr->user_addr = *user;
+ sk->protinfo.nr->source_addr = *source;
}
- sk->nr->device = dev;
+ sk->protinfo.nr->device = dev;
nr_insert_socket(sk);
sk->zapped = 0;
@@ -775,24 +714,27 @@
struct sockaddr_ax25 *addr = (struct sockaddr_ax25 *)uaddr;
ax25_address *user, *source = NULL;
struct device *dev;
-
+
if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
sock->state = SS_CONNECTED;
return 0; /* Connect completed during a ERESTARTSYS event */
}
-
+
if (sk->state == TCP_CLOSE && sock->state == SS_CONNECTING) {
sock->state = SS_UNCONNECTED;
return -ECONNREFUSED;
}
-
+
if (sk->state == TCP_ESTABLISHED)
return -EISCONN; /* No reconnect on a seqpacket socket */
-
+
sk->state = TCP_CLOSE;
sock->state = SS_UNCONNECTED;
- if (addr_len != sizeof(struct sockaddr_ax25))
+ if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25))
+ return -EINVAL;
+
+ if (addr->sax25_family != AF_NETROM)
return -EINVAL;
if (sk->zapped) { /* Must bind first - autobinding in this may or may not work */
@@ -809,30 +751,29 @@
user = source;
}
- sk->nr->user_addr = *user;
- sk->nr->source_addr = *source;
- sk->nr->device = dev;
+ sk->protinfo.nr->user_addr = *user;
+ sk->protinfo.nr->source_addr = *source;
+ sk->protinfo.nr->device = dev;
nr_insert_socket(sk); /* Finish the bind */
}
- sk->nr->dest_addr = addr->sax25_call;
+ sk->protinfo.nr->dest_addr = addr->sax25_call;
- while (nr_find_socket((unsigned char)circuit / 256, (unsigned char)circuit % 256) != NULL)
- circuit++;
+ circuit = nr_find_next_circuit();
- sk->nr->my_index = circuit / 256;
- sk->nr->my_id = circuit % 256;
+ sk->protinfo.nr->my_index = circuit / 256;
+ sk->protinfo.nr->my_id = circuit % 256;
circuit++;
-
+
/* Move to connecting socket, start sending Connect Requests */
- sock->state = SS_CONNECTING;
- sk->state = TCP_SYN_SENT;
+ sock->state = SS_CONNECTING;
+ sk->state = TCP_SYN_SENT;
nr_establish_data_link(sk);
- sk->nr->state = NR_STATE_1;
+ sk->protinfo.nr->state = NR_STATE_1;
nr_set_timer(sk);
-
+
/* Now the loop */
if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
return -EINPROGRESS;
@@ -855,14 +796,14 @@
sock->state = SS_UNCONNECTED;
return sock_error(sk); /* Always set at this point */
}
-
+
sock->state = SS_CONNECTED;
sti();
-
+
return 0;
}
-
+
static int nr_socketpair(struct socket *sock1, struct socket *sock2)
{
return -EOPNOTSUPP;
@@ -874,19 +815,20 @@
struct sock *newsk;
struct sk_buff *skb;
- if (newsock->data)
- sk_free(newsock->data);
+ if (newsock->data != NULL)
+ nr_destroy_socket((struct sock *)newsock->data);
newsock->data = NULL;
-
- sk = (struct sock *)sock->data;
+
+ if ((sk = (struct sock *)sock->data) == NULL)
+ return -EINVAL;
if (sk->type != SOCK_SEQPACKET)
return -EOPNOTSUPP;
-
+
if (sk->state != TCP_LISTEN)
return -EINVAL;
-
+
/*
* The write queue this time is holding sockets ready to use
* hooked into the SABM we saved
@@ -896,7 +838,7 @@
if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
if (flags & O_NONBLOCK) {
sti();
- return 0;
+ return -EWOULDBLOCK;
}
interruptible_sleep_on(sk->sleep);
if (current->signal & ~current->blocked) {
@@ -925,35 +867,34 @@
int *uaddr_len, int peer)
{
struct full_sockaddr_ax25 *sax = (struct full_sockaddr_ax25 *)uaddr;
- struct sock *sk;
-
- sk = (struct sock *)sock->data;
-
+ struct sock *sk = (struct sock *)sock->data;
+
if (peer != 0) {
if (sk->state != TCP_ESTABLISHED)
return -ENOTCONN;
sax->fsa_ax25.sax25_family = AF_NETROM;
sax->fsa_ax25.sax25_ndigis = 1;
- sax->fsa_ax25.sax25_call = sk->nr->user_addr;
- sax->fsa_digipeater[0] = sk->nr->dest_addr;
+ sax->fsa_ax25.sax25_call = sk->protinfo.nr->user_addr;
+ sax->fsa_digipeater[0] = sk->protinfo.nr->dest_addr;
*uaddr_len = sizeof(struct full_sockaddr_ax25);
} else {
sax->fsa_ax25.sax25_family = AF_NETROM;
sax->fsa_ax25.sax25_ndigis = 0;
- sax->fsa_ax25.sax25_call = sk->nr->source_addr;
+ sax->fsa_ax25.sax25_call = sk->protinfo.nr->source_addr;
*uaddr_len = sizeof(struct sockaddr_ax25);
}
return 0;
}
-
+
int nr_rx_frame(struct sk_buff *skb, struct device *dev)
{
struct sock *sk;
struct sock *make;
ax25_address *src, *dest, *user;
unsigned short circuit_index, circuit_id;
- unsigned short frametype, window, timeout;
+ unsigned short peer_circuit_index, peer_circuit_id;
+ unsigned short frametype, flags, window, timeout;
skb->sk = NULL; /* Initially we don't know who it's for */
@@ -964,47 +905,74 @@
src = (ax25_address *)(skb->data + 0);
dest = (ax25_address *)(skb->data + 7);
- circuit_index = skb->data[15];
- circuit_id = skb->data[16];
- frametype = skb->data[19];
+ circuit_index = skb->data[15];
+ circuit_id = skb->data[16];
+ peer_circuit_index = skb->data[17];
+ peer_circuit_id = skb->data[18];
+ frametype = skb->data[19] & 0x0F;
+ flags = skb->data[19] & 0xF0;
#ifdef CONFIG_INET
/*
* Check for an incoming IP over NET/ROM frame.
*/
- if ((frametype & 0x0F) == NR_PROTOEXT && circuit_index == NR_PROTO_IP && circuit_id == NR_PROTO_IP) {
+ if (frametype == NR_PROTOEXT && circuit_index == NR_PROTO_IP && circuit_id == NR_PROTO_IP) {
skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
- skb->h.raw = skb->data;
+ skb->h.raw = skb->data;
return nr_rx_ip(skb, dev);
- }
+ }
#endif
/*
* Find an existing socket connection, based on circuit ID, if it's
* a Connect Request base it on their circuit ID.
+ *
+ * Circuit ID 0/0 is not valid but it could still be a "reset" for
+ * a circuit that no longer exists at the other end...
*/
- if (((frametype & 0x0F) != NR_CONNREQ && (sk = nr_find_socket(circuit_index, circuit_id)) != NULL) ||
- ((frametype & 0x0F) == NR_CONNREQ && (sk = nr_find_peer(circuit_index, circuit_id)) != NULL)) {
+
+ sk = NULL;
+
+ if (circuit_index == 0 && circuit_id == 0) {
+ if (frametype == NR_CONNACK && flags == NR_CHOKE_FLAG)
+ sk = nr_find_peer(peer_circuit_index, peer_circuit_id);
+ } else {
+ if (frametype == NR_CONNREQ)
+ sk = nr_find_peer(circuit_index, circuit_id);
+ else
+ sk = nr_find_socket(circuit_index, circuit_id);
+ }
+
+ if (sk != NULL) {
skb->h.raw = skb->data;
- if ((frametype & 0x0F) == NR_CONNACK && skb->len == 22)
- sk->nr->bpqext = 1;
+ if (frametype == NR_CONNACK && skb->len == 22)
+ sk->protinfo.nr->bpqext = 1;
else
- sk->nr->bpqext = 0;
+ sk->protinfo.nr->bpqext = 0;
return nr_process_rx_frame(sk, skb);
}
- if ((frametype & 0x0F) != NR_CONNREQ)
+ /*
+ * Now it should be a CONNREQ.
+ */
+ if (frametype != NR_CONNREQ) {
+ /*
+ * Never reply to a CONNACK/CHOKE.
+ */
+ if (frametype != NR_CONNACK || flags != NR_CHOKE_FLAG)
+ nr_transmit_dm(skb, 1);
return 0;
-
+ }
+
sk = nr_find_listener(dest);
user = (ax25_address *)(skb->data + 21);
if (sk == NULL || sk->ack_backlog == sk->max_ack_backlog || (make = nr_make_new(sk)) == NULL) {
- nr_transmit_dm(skb);
+ nr_transmit_dm(skb, 0);
return 0;
}
@@ -1014,40 +982,42 @@
make->state = TCP_ESTABLISHED;
/* Fill in his circuit details */
- make->nr->source_addr = *dest;
- make->nr->dest_addr = *src;
- make->nr->user_addr = *user;
+ make->protinfo.nr->source_addr = *dest;
+ make->protinfo.nr->dest_addr = *src;
+ make->protinfo.nr->user_addr = *user;
- make->nr->your_index = circuit_index;
- make->nr->your_id = circuit_id;
+ make->protinfo.nr->your_index = circuit_index;
+ make->protinfo.nr->your_id = circuit_id;
+
+ circuit = nr_find_next_circuit();
+
+ make->protinfo.nr->my_index = circuit / 256;
+ make->protinfo.nr->my_id = circuit % 256;
- make->nr->my_index = circuit / 256;
- make->nr->my_id = circuit % 256;
-
circuit++;
/* Window negotiation */
- if (window < make->window)
- make->window = window;
+ if (window < make->protinfo.nr->window)
+ make->protinfo.nr->window = window;
/* L4 timeout negotiation */
if (skb->len == 37) {
timeout = skb->data[36] * 256 + skb->data[35];
- if (timeout * PR_SLOWHZ < make->nr->rtt * 2)
- make->nr->rtt = (timeout * PR_SLOWHZ) / 2;
- make->nr->bpqext = 1;
+ if (timeout * NR_SLOWHZ < make->protinfo.nr->t1)
+ make->protinfo.nr->t1 = timeout * NR_SLOWHZ;
+ make->protinfo.nr->bpqext = 1;
} else {
- make->nr->bpqext = 0;
+ make->protinfo.nr->bpqext = 0;
}
nr_write_internal(make, NR_CONNACK);
- make->nr->condition = 0x00;
- make->nr->vs = 0;
- make->nr->va = 0;
- make->nr->vr = 0;
- make->nr->vl = 0;
- make->nr->state = NR_STATE_3;
+ make->protinfo.nr->condition = 0x00;
+ make->protinfo.nr->vs = 0;
+ make->protinfo.nr->va = 0;
+ make->protinfo.nr->vr = 0;
+ make->protinfo.nr->vl = 0;
+ make->protinfo.nr->state = NR_STATE_3;
sk->ack_backlog++;
make->pair = sk;
@@ -1072,7 +1042,7 @@
struct sk_buff *skb;
unsigned char *asmptr;
int size;
-
+
if (sk->err)
return sock_error(sk);
@@ -1082,14 +1052,19 @@
if (sk->zapped)
return -EADDRNOTAVAIL;
- if (sk->nr->device == NULL)
+ if (sk->shutdown & SEND_SHUTDOWN) {
+ send_sig(SIGPIPE, current, 0);
+ return -EPIPE;
+ }
+
+ if (sk->protinfo.nr->device == NULL)
return -ENETUNREACH;
-
+
if (usax) {
if (msg->msg_namelen < sizeof(sax))
return -EINVAL;
sax = *usax;
- if (ax25cmp(&sk->nr->dest_addr, &sax.sax25_call) != 0)
+ if (ax25cmp(&sk->protinfo.nr->dest_addr, &sax.sax25_call) != 0)
return -EISCONN;
if (sax.sax25_family != AF_NETROM)
return -EINVAL;
@@ -1097,9 +1072,9 @@
if (sk->state != TCP_ESTABLISHED)
return -ENOTCONN;
sax.sax25_family = AF_NETROM;
- sax.sax25_call = sk->nr->dest_addr;
+ sax.sax25_call = sk->protinfo.nr->dest_addr;
}
-
+
if (sk->debug)
printk("NET/ROM: sendto: Addresses built.\n");
@@ -1114,10 +1089,9 @@
skb->sk = sk;
skb->free = 1;
- skb->arp = 1;
skb_reserve(skb, size - len);
-
+
/*
* Push down the NET/ROM header
*/
@@ -1129,12 +1103,12 @@
/* Build a NET/ROM Transport header */
- *asmptr++ = sk->nr->your_index;
- *asmptr++ = sk->nr->your_id;
+ *asmptr++ = sk->protinfo.nr->your_index;
+ *asmptr++ = sk->protinfo.nr->your_id;
*asmptr++ = 0; /* To be filled in later */
*asmptr++ = 0; /* Ditto */
*asmptr++ = NR_INFO;
-
+
if (sk->debug)
printk("Built header.\n");
@@ -1145,7 +1119,7 @@
skb->h.raw = skb_put(skb, len);
asmptr = skb->h.raw;
-
+
if (sk->debug)
printk("NET/ROM: Appending user data\n");
@@ -1185,6 +1159,7 @@
* This works for seqpacket too. The receiver has ordered the queue for
* us! We do one quick check first though
*/
+
if (sk->state != TCP_ESTABLISHED)
return -ENOTCONN;
@@ -1192,21 +1167,14 @@
if ((skb = skb_recv_datagram(sk, flags, noblock, &er)) == NULL)
return er;
- if (!sk->nr->hdrincl) {
- skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
- skb->h.raw = skb->data;
- }
+ skb->h.raw = skb->data;
copied = (size < skb->len) ? size : skb->len;
skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
-
- if (sax != NULL) {
- struct sockaddr_ax25 addr;
-
- addr.sax25_family = AF_NETROM;
- memcpy(&addr.sax25_call, skb->data + 7, AX25_ADDR_LEN);
- *sax = addr;
+ if (sax != NULL) {
+ sax->sax25_family = AF_NETROM;
+ memcpy(&sax->sax25_call, skb->data + 7, AX25_ADDR_LEN);
*addr_len = sizeof(*sax);
}
@@ -1232,34 +1200,36 @@
{
struct sock *sk = (struct sock *)sock->data;
int err;
- long amount = 0;
switch (cmd) {
- case TIOCOUTQ:
- if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned long))) != 0)
+ case TIOCOUTQ: {
+ long amount;
+ if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int))) != 0)
return err;
amount = sk->sndbuf - sk->wmem_alloc;
if (amount < 0)
amount = 0;
- put_fs_long(amount, (unsigned long *)arg);
+ put_fs_long(amount, (int *)arg);
return 0;
+ }
case TIOCINQ: {
struct sk_buff *skb;
+ long amount = 0L;
/* These two are safe on a single CPU system as only user tasks fiddle here */
if ((skb = skb_peek(&sk->receive_queue)) != NULL)
- amount = skb->len - 20;
- if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned long))) != 0)
+ amount = skb->len;
+ if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int))) != 0)
return err;
- put_fs_long(amount, (unsigned long *)arg);
+ put_fs_long(amount, (int *)arg);
return 0;
}
case SIOCGSTAMP:
if (sk != NULL) {
- if (sk->stamp.tv_sec==0)
+ if (sk->stamp.tv_sec == 0)
return -ENOENT;
- if ((err = verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval))) != 0)
+ if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct timeval))) != 0)
return err;
memcpy_tofs((void *)arg, &sk->stamp, sizeof(struct timeval));
return 0;
@@ -1281,34 +1251,9 @@
case SIOCADDRT:
case SIOCDELRT:
case SIOCNRDECOBS:
- case SIOCNRRTCTL:
if (!suser()) return -EPERM;
return nr_rt_ioctl(cmd, (void *)arg);
- case SIOCNRGETPARMS: {
- struct nr_parms_struct nr_parms;
- if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct nr_parms_struct))) != 0)
- return err;
- memcpy_fromfs(&nr_parms, (void *)arg, sizeof(struct nr_parms_struct));
- nr_parms = nr_default;
- memcpy_tofs((void *)arg, &nr_parms, sizeof(struct nr_parms_struct));
- return 0;
- }
-
- case SIOCNRSETPARMS: {
- struct nr_parms_struct nr_parms;
- if (!suser()) return -EPERM;
- if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(struct nr_parms_struct))) != 0)
- return err;
- memcpy_fromfs(&nr_parms, (void *)arg, sizeof(struct nr_parms_struct));
- nr_default = nr_parms;
- return 0;
- }
-
- case SIOCNRCTLCON:
- if (!suser()) return -EPERM;
- return nr_ctl_ioctl(cmd, (void *)arg);
-
default:
return dev_ioctl(cmd, (void *)arg);
}
@@ -1325,43 +1270,49 @@
int len = 0;
off_t pos = 0;
off_t begin = 0;
-
+
cli();
- len += sprintf(buffer, "user_addr dest_node src_node dev my your st vs vr va t1 t2 n2 rtt wnd paclen Snd-Q Rcv-Q\n");
+ len += sprintf(buffer, "user_addr dest_node src_node dev my your st vs vr va t1 t2 t4 idle n2 wnd Snd-Q Rcv-Q Inode\n");
for (s = nr_list; s != NULL; s = s->next) {
- if ((dev = s->nr->device) == NULL)
+ if ((dev = s->protinfo.nr->device) == NULL)
devname = "???";
else
devname = dev->name;
-
+
len += sprintf(buffer + len, "%-9s ",
- ax2asc(&s->nr->user_addr));
+ ax2asc(&s->protinfo.nr->user_addr));
len += sprintf(buffer + len, "%-9s ",
- ax2asc(&s->nr->dest_addr));
- len += sprintf(buffer + len, "%-9s %-3s %02X/%02X %02X/%02X %2d %3d %3d %3d %3d/%03d %2d/%02d %2d/%02d %3d %3d %6d %5d %5d\n",
- ax2asc(&s->nr->source_addr),
- devname, s->nr->my_index, s->nr->my_id,
- s->nr->your_index, s->nr->your_id,
- s->nr->state,
- s->nr->vs, s->nr->vr, s->nr->va,
- s->nr->t1timer / PR_SLOWHZ,
- s->nr->t1 / PR_SLOWHZ,
- s->nr->t2timer / PR_SLOWHZ,
- s->nr->t2 / PR_SLOWHZ,
- s->nr->n2count, s->nr->n2,
- s->nr->rtt / PR_SLOWHZ,
- s->window, s->nr->paclen,
- s->wmem_alloc, s->rmem_alloc);
-
+ ax2asc(&s->protinfo.nr->dest_addr));
+ len += sprintf(buffer + len, "%-9s %-3s %02X/%02X %02X/%02X %2d %3d %3d %3d %3d/%03d %2d/%02d %3d/%03d %3d/%03d %2d/%02d %3d %5d %5d %ld\n",
+ ax2asc(&s->protinfo.nr->source_addr),
+ devname, s->protinfo.nr->my_index, s->protinfo.nr->my_id,
+ s->protinfo.nr->your_index, s->protinfo.nr->your_id,
+ s->protinfo.nr->state,
+ s->protinfo.nr->vs, s->protinfo.nr->vr, s->protinfo.nr->va,
+ s->protinfo.nr->t1timer / NR_SLOWHZ,
+ s->protinfo.nr->t1 / NR_SLOWHZ,
+ s->protinfo.nr->t2timer / NR_SLOWHZ,
+ s->protinfo.nr->t2 / NR_SLOWHZ,
+ s->protinfo.nr->t4timer / NR_SLOWHZ,
+ s->protinfo.nr->t4 / NR_SLOWHZ,
+ 0,
+ 0,
+ s->protinfo.nr->n2count,
+ s->protinfo.nr->n2,
+ s->protinfo.nr->window,
+ s->wmem_alloc, s->rmem_alloc,
+ s->socket && SOCK_INODE(s->socket) ?
+ SOCK_INODE(s->socket)->i_ino : 0);
+
pos = begin + len;
if (pos < offset) {
len = 0;
begin = pos;
}
-
+
if (pos > offset + length)
break;
}
@@ -1378,7 +1329,7 @@
static struct proto_ops nr_proto_ops = {
AF_NETROM,
-
+
nr_create,
nr_dup,
nr_release,
@@ -1403,42 +1354,103 @@
0
};
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry proc_net_nr = {
+ PROC_NET_NR, 2, "nr",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ nr_get_info
+};
+static struct proc_dir_entry proc_net_nr_neigh = {
+ PROC_NET_NR_NEIGH, 8, "nr_neigh",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ nr_neigh_get_info
+};
+static struct proc_dir_entry proc_net_nr_nodes = {
+ PROC_NET_NR_NODES, 8, "nr_nodes",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ nr_nodes_get_info
+};
+#endif
+
+static struct device dev_nr[] = {
+ {"nr0", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, nr_init},
+ {"nr1", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, nr_init},
+ {"nr2", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, nr_init},
+ {"nr3", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, nr_init}
+};
+
void nr_proto_init(struct net_proto *pro)
{
+ int i;
+
sock_register(nr_proto_ops.family, &nr_proto_ops);
register_netdevice_notifier(&nr_dev_notifier);
- printk(KERN_INFO "G4KLX NET/ROM for Linux. Version 0.5 for AX25.032 Linux 2.0\n");
+ printk(KERN_INFO "G4KLX NET/ROM for Linux. Version 0.6 for AX25.035 Linux 2.0\n");
- nr_default.quality = NR_DEFAULT_QUAL;
- nr_default.obs_count = NR_DEFAULT_OBS;
- nr_default.ttl = NR_DEFAULT_TTL;
- nr_default.timeout = NR_DEFAULT_T1;
- nr_default.ack_delay = NR_DEFAULT_T2;
- nr_default.busy_delay = NR_DEFAULT_T4;
- nr_default.tries = NR_DEFAULT_N2;
- nr_default.window = NR_DEFAULT_WINDOW;
- nr_default.paclen = NR_DEFAULT_PACLEN;
+ if (!ax25_protocol_register(AX25_P_NETROM, nr_route_frame))
+ printk(KERN_ERR "NET/ROM unable to register protocol with AX.25\n");
+ if (!ax25_linkfail_register(nr_link_failed))
+ printk(KERN_ERR "NET/ROM unable to register linkfail handler with AX.25\n");
+
+ for (i = 0; i < 4; i++)
+ register_netdev(&dev_nr[i]);
+
+ nr_register_sysctl();
+
+ nr_loopback_init();
#ifdef CONFIG_PROC_FS
- proc_net_register(&(struct proc_dir_entry) {
- PROC_NET_NR, 2, "nr",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- nr_get_info
- });
- proc_net_register(&(struct proc_dir_entry) {
- PROC_NET_NR_NEIGH, 8, "nr_neigh",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- nr_neigh_get_info
- });
- proc_net_register(&(struct proc_dir_entry) {
- PROC_NET_NR_NODES, 8, "nr_nodes",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- nr_nodes_get_info
- });
+ proc_net_register(&proc_net_nr);
+ proc_net_register(&proc_net_nr_neigh);
+ proc_net_register(&proc_net_nr_nodes);
#endif
}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+ nr_proto_init(NULL);
+
+ register_symtab(NULL);
+
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ int i;
+
+#ifdef CONFIG_PROC_FS
+ proc_net_unregister(PROC_NET_NR);
+ proc_net_unregister(PROC_NET_NR_NEIGH);
+ proc_net_unregister(PROC_NET_NR_NODES);
+#endif
+ nr_loopback_clear();
+
+ nr_rt_free();
+
+ ax25_protocol_release(AX25_P_NETROM);
+ ax25_linkfail_release(nr_link_failed);
+
+ unregister_netdevice_notifier(&nr_dev_notifier);
+
+ nr_unregister_sysctl();
+
+ sock_unregister(AF_NETROM);
+
+ for (i = 0; i < 4; i++) {
+ if (dev_nr[i].priv != NULL) {
+ kfree(dev_nr[i].priv);
+ dev_nr[i].priv = NULL;
+ unregister_netdev(&dev_nr[i]);
+ }
+ }
+}
+
+#endif
#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov