diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-05-07 02:55:41 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-05-07 02:55:41 +0000 |
commit | dcec8a13bf565e47942a1751a9cec21bec5648fe (patch) | |
tree | 548b69625b18cc2e88c3e68d0923be546c9ebb03 /net/netrom | |
parent | 2e0f55e79c49509b7ff70ff1a10e1e9e90a3dfd4 (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/Makefile | 3 | ||||
-rw-r--r-- | net/netrom/af_netrom.c | 100 | ||||
-rw-r--r-- | net/netrom/nr_in.c | 5 | ||||
-rw-r--r-- | net/netrom/nr_loopback.c | 107 | ||||
-rw-r--r-- | net/netrom/nr_route.c | 8 | ||||
-rw-r--r-- | net/netrom/nr_subr.c | 18 |
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; |