summaryrefslogtreecommitdiffstats
path: root/net/netrom
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-05-07 02:55:41 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-05-07 02:55:41 +0000
commitdcec8a13bf565e47942a1751a9cec21bec5648fe (patch)
tree548b69625b18cc2e88c3e68d0923be546c9ebb03 /net/netrom
parent2e0f55e79c49509b7ff70ff1a10e1e9e90a3dfd4 (diff)
o Merge with Linux 2.1.99.
o Fix ancient bug in the ELF loader making ldd crash. o Fix ancient bug in the keyboard code for SGI, SNI and Jazz.
Diffstat (limited to 'net/netrom')
-rw-r--r--net/netrom/Makefile3
-rw-r--r--net/netrom/af_netrom.c100
-rw-r--r--net/netrom/nr_in.c5
-rw-r--r--net/netrom/nr_loopback.c107
-rw-r--r--net/netrom/nr_route.c8
-rw-r--r--net/netrom/nr_subr.c18
6 files changed, 207 insertions, 34 deletions
diff --git a/net/netrom/Makefile b/net/netrom/Makefile
index 4ac78639b..1afcfd8e7 100644
--- a/net/netrom/Makefile
+++ b/net/netrom/Makefile
@@ -8,7 +8,8 @@
# Note 2! The CFLAGS definition is now in the main makefile...
O_TARGET := netrom.o
-O_OBJS := af_netrom.o nr_dev.o nr_in.o nr_out.o nr_route.o nr_subr.o nr_timer.o
+O_OBJS := af_netrom.o nr_dev.o nr_in.o nr_loopback.o nr_out.o nr_route.o \
+ nr_subr.o nr_timer.o
M_OBJS := $(O_TARGET)
ifeq ($(CONFIG_SYSCTL),y)
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 9d8a206da..59d3dacfb 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -259,6 +259,28 @@ static struct sock *nr_find_peer(unsigned char index, unsigned char id)
}
/*
+ * Find next free circuit ID.
+ */
+static unsigned short nr_find_next_circuit(void)
+{
+ unsigned short id = circuit;
+ unsigned char i, j;
+
+ for (;;) {
+ 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 *);
@@ -535,12 +557,12 @@ static int nr_release(struct socket *sock, struct socket *peer)
switch (sk->protinfo.nr->state) {
case NR_STATE_0:
+ case NR_STATE_1:
case NR_STATE_2:
nr_disconnect(sk, 0);
nr_destroy_socket(sk);
break;
- case NR_STATE_1:
case NR_STATE_3:
nr_clear_queues(sk);
sk->protinfo.nr->n2count = 0;
@@ -670,8 +692,7 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
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->protinfo.nr->my_index = circuit / 256;
sk->protinfo.nr->my_id = circuit % 256;
@@ -764,7 +785,6 @@ static int nr_accept(struct socket *sock, struct socket *newsock, int flags)
sti();
/* Now attach up the new socket */
- skb->sk = NULL;
kfree_skb(skb);
sk->ack_backlog--;
newsock->sk = newsk;
@@ -802,7 +822,8 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
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 */
@@ -813,28 +834,46 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
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] & 0x0F;
+ 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 == 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 != NR_CONNREQ && (sk = nr_find_socket(circuit_index, circuit_id)) != NULL) ||
- (frametype == 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 == NR_CONNACK && skb->len == 22)
@@ -845,15 +884,17 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
return nr_process_rx_frame(sk, skb);
}
- switch (frametype) {
- case NR_CONNREQ:
- break;
- case NR_DISCREQ:
- case NR_DISCACK:
- return 0;
- default:
- nr_transmit_dm(skb);
- return 0;
+ /*
+ * 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_refusal(skb, 1);
+
+ return 0;
}
sk = nr_find_listener(dest);
@@ -861,7 +902,7 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
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_refusal(skb, 0);
return 0;
}
@@ -878,6 +919,8 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
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;
@@ -1131,7 +1174,7 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length, int
cli();
- 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\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->protinfo.nr->device) == NULL)
@@ -1143,7 +1186,7 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length, int
ax2asc(&s->protinfo.nr->user_addr));
len += sprintf(buffer + len, "%-9s ",
ax2asc(&s->protinfo.nr->dest_addr));
- len += sprintf(buffer + len, "%-9s %-3s %02X/%02X %02X/%02X %2d %3d %3d %3d %3lu/%03lu %2lu/%02lu %3lu/%03lu %3lu/%03lu %2d/%02d %3d %5d %5d\n",
+ len += sprintf(buffer + len, "%-9s %-3s %02X/%02X %02X/%02X %2d %3d %3d %3d %3lu/%03lu %2lu/%02lu %3lu/%03lu %3lu/%03lu %2d/%02d %3d %5d %5d %ld\n",
ax2asc(&s->protinfo.nr->source_addr),
devname,
s->protinfo.nr->my_index,
@@ -1166,7 +1209,8 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length, int
s->protinfo.nr->n2,
s->protinfo.nr->window,
atomic_read(&s->wmem_alloc),
- atomic_read(&s->rmem_alloc));
+ atomic_read(&s->rmem_alloc),
+ s->socket != NULL ? s->socket->inode->i_ino : 0L);
pos = begin + len;
@@ -1273,6 +1317,8 @@ __initfunc(void nr_proto_init(struct net_proto *pro))
nr_register_sysctl();
#endif
+ nr_loopback_init();
+
#ifdef CONFIG_PROC_FS
proc_net_register(&proc_net_nr);
proc_net_register(&proc_net_nr_neigh);
@@ -1305,6 +1351,8 @@ void cleanup_module(void)
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);
diff --git a/net/netrom/nr_in.c b/net/netrom/nr_in.c
index ac32cd704..fadf69de8 100644
--- a/net/netrom/nr_in.c
+++ b/net/netrom/nr_in.c
@@ -129,6 +129,10 @@ static int nr_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype
{
switch (frametype) {
+ case NR_CONNACK | NR_CHOKE_FLAG:
+ nr_disconnect(sk, ECONNRESET);
+ break;
+
case NR_DISCREQ:
nr_write_internal(sk, NR_DISCACK);
@@ -170,6 +174,7 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
nr_disconnect(sk, 0);
break;
+ case NR_CONNACK | NR_CHOKE_FLAG:
case NR_DISCACK:
nr_disconnect(sk, ECONNRESET);
break;
diff --git a/net/netrom/nr_loopback.c b/net/netrom/nr_loopback.c
new file mode 100644
index 000000000..ba9644cbe
--- /dev/null
+++ b/net/netrom/nr_loopback.c
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ *
+ */
+
+#include <linux/config.h>
+#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/timer.h>
+#include <net/ax25.h>
+#include <linux/skbuff.h>
+#include <net/netrom.h>
+
+static struct sk_buff_head loopback_queue;
+static struct timer_list loopback_timer;
+
+static void nr_set_loopback_timer(void);
+
+void nr_loopback_init(void)
+{
+ skb_queue_head_init(&loopback_queue);
+
+ init_timer(&loopback_timer);
+}
+
+static int nr_loopback_running(void)
+{
+ return (loopback_timer.prev != NULL || loopback_timer.next != NULL);
+}
+
+int nr_loopback_queue(struct sk_buff *skb)
+{
+ struct sk_buff *skbn;
+
+ skbn = skb_clone(skb, GFP_ATOMIC);
+
+ kfree_skb(skb);
+
+ if (skbn != NULL) {
+ skb_queue_tail(&loopback_queue, skbn);
+
+ if (!nr_loopback_running())
+ nr_set_loopback_timer();
+ }
+
+ return 1;
+}
+
+static void nr_loopback_timer(unsigned long);
+
+static void nr_set_loopback_timer(void)
+{
+ del_timer(&loopback_timer);
+
+ loopback_timer.data = 0;
+ loopback_timer.function = &nr_loopback_timer;
+ loopback_timer.expires = jiffies + 10;
+
+ add_timer(&loopback_timer);
+}
+
+static void nr_loopback_timer(unsigned long param)
+{
+ struct sk_buff *skb;
+ ax25_address *nr_dest;
+ struct device *dev;
+
+ while ((skb = skb_dequeue(&loopback_queue)) != NULL) {
+ nr_dest = (ax25_address *)(skb->data + 7);
+
+ if ((dev = nr_dev_get(nr_dest)) == NULL) {
+ kfree_skb(skb);
+ continue;
+ }
+
+ if (nr_rx_frame(skb, dev) == 0)
+ kfree_skb(skb);
+ }
+}
+
+#ifdef MODULE
+
+void nr_loopback_clear(void)
+{
+ struct sk_buff *skb;
+
+ del_timer(&loopback_timer);
+
+ while ((skb = skb_dequeue(&loopback_queue)) != NULL)
+ kfree_skb(skb);
+}
+
+#endif
+
+#endif
diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c
index ffbb240c4..26f5ac8dd 100644
--- a/net/netrom/nr_route.c
+++ b/net/netrom/nr_route.c
@@ -697,8 +697,12 @@ int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat,
ax25->ax25_dev->dev, 0, sysctl_netrom_obsolescence_count_initialiser);
- if ((dev = nr_dev_get(nr_dest)) != NULL) /* Its for me */
- return nr_rx_frame(skb, dev);
+ if ((dev = nr_dev_get(nr_dest)) != NULL) { /* Its for me */
+ if (ax25 == NULL) /* Its from me */
+ return nr_loopback_queue(skb);
+ else
+ return nr_rx_frame(skb, dev);
+ }
if (!sysctl_netrom_routing_control && ax25 != NULL)
return 0;
diff --git a/net/netrom/nr_subr.c b/net/netrom/nr_subr.c
index 7ae69fe07..096ca3a8f 100644
--- a/net/netrom/nr_subr.c
+++ b/net/netrom/nr_subr.c
@@ -229,7 +229,7 @@ void nr_write_internal(struct sock *sk, int frametype)
* This routine is called when a Connect Acknowledge with the Choke Flag
* set is needed to refuse a connection.
*/
-void nr_transmit_dm(struct sk_buff *skb)
+void nr_transmit_refusal(struct sk_buff *skb, int mine)
{
struct sk_buff *skbn;
unsigned char *dptr;
@@ -258,10 +258,18 @@ void nr_transmit_dm(struct sk_buff *skb)
*dptr++ = sysctl_netrom_network_ttl_initialiser;
- *dptr++ = skb->data[15];
- *dptr++ = skb->data[16];
- *dptr++ = 0;
- *dptr++ = 0;
+ if (mine) {
+ *dptr++ = 0;
+ *dptr++ = 0;
+ *dptr++ = skb->data[15];
+ *dptr++ = skb->data[16];
+ } else {
+ *dptr++ = skb->data[15];
+ *dptr++ = skb->data[16];
+ *dptr++ = 0;
+ *dptr++ = 0;
+ }
+
*dptr++ = NR_CONNACK | NR_CHOKE_FLAG;
*dptr++ = 0;