aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavem <davem>2001-11-29 07:39:06 +0000
committerdavem <davem>2001-11-29 07:39:06 +0000
commit0e49c3417c2e5850cb7bf2b0a940d9557406a3f3 (patch)
treeb57259b538beeb0bf34a0204a9df026f5884137f
parent73554d7ce4eb2aa826526b99554edbba5f55677c (diff)
downloadnetdev-vger-cvs-0e49c3417c2e5850cb7bf2b0a940d9557406a3f3.tar.gz
DecNET updates from Steven Whitehouse:
1) Fix port allocation bug. 2) Doc updates.
-rw-r--r--Documentation/networking/decnet.txt21
-rw-r--r--net/decnet/README2
-rw-r--r--net/decnet/af_decnet.c158
3 files changed, 126 insertions, 55 deletions
diff --git a/Documentation/networking/decnet.txt b/Documentation/networking/decnet.txt
index 2b290ef8a..b799e6e49 100644
--- a/Documentation/networking/decnet.txt
+++ b/Documentation/networking/decnet.txt
@@ -4,20 +4,9 @@
1) Other documentation....
o Project Home Pages
- http://www.sucs.swan.ac.uk/~rohan/DECnet/index.html - Kernel info
+ http://www.chygwyn.com/DECnet/ - Kernel info
http://linux-decnet.sourceforge.net/ - Userland tools
-
- o FTP sites
- ftp://ftp.sucs.swan.ac.uk/pub/Linux/DECnet/
- - Swansea University Computer Society DECnet Archive
- (contains kernel patches and info)
- - Mirror of userland tools on ftp.dreamtime.org
- - Mirror of Alexey Kuznetsov's iproute2 package and
- other utilities
-
- ftp://linux-decnet.sourceforge.net/pub/linux-decnet/
- - Patrick Caulfield's archive of userland tools and
- Eduardo Serrat's kernel patches
+ http://www.sourceforge.net/projects/linux-decnet/ - Status page
2) Configuring the kernel
@@ -33,6 +22,12 @@ you'll need the following options as well...
CONFIG_DECNET_ROUTER (to be able to add/delete routes)
CONFIG_NETFILTER (will be required for the DECnet routing daemon)
+ CONFIG_DECNET_ROUTE_FWMARK is optional
+
+Don't turn on SIOCGIFCONF support for DECnet unless you are really sure
+that you need it, in general you won't and it can cause ifconfig to
+malfunction.
+
3) Command line options
The kernel command line takes options looking like the following:
diff --git a/net/decnet/README b/net/decnet/README
index 9384fa322..4d0d235ab 100644
--- a/net/decnet/README
+++ b/net/decnet/README
@@ -3,6 +3,6 @@
The documentation for this kernel subsystem is available in the
Documentation/networking subdirctory of this distribution and also
-on line at http://www.sucs.swan.ac.uk/~rohan/DECnet/index.html.
+on line at http://www.chygwyn.com/DECnet/
Steve Whitehouse <SteveW@ACM.org>
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 6b01f3d18..bc17c49cb 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -36,6 +36,7 @@
* Steve Whitehouse: Removed unused code. Fix to use sk->allocation
* when required.
* Patrick Caulfield: /proc/net/decnet now has object name/number
+ * Steve Whitehouse: Fixed local port allocation, hashed sk list
*/
@@ -139,9 +140,13 @@ static void dn_keepalive(struct sock *sk);
dn_address decnet_address = 0;
unsigned char decnet_ether_address[ETH_ALEN] = { 0xAA, 0x00, 0x04, 0x00, 0x00, 0x00 };
+#define DN_SK_HASH_SHIFT 8
+#define DN_SK_HASH_SIZE (1 << DN_SK_HASH_SHIFT)
+#define DN_SK_HASH_MASK (DN_SK_HASH_SIZE - 1)
+
static struct proto_ops dn_proto_ops;
rwlock_t dn_hash_lock = RW_LOCK_UNLOCKED;
-static struct sock *dn_sklist;
+static struct sock *dn_sk_hash[DN_SK_HASH_SIZE];
static struct sock *dn_wild_sk;
static int __dn_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen, int flags);
@@ -154,18 +159,38 @@ static struct sock **dn_find_list(struct sock *sk)
if (scp->addr.sdn_flags & SDF_WILD)
return dn_wild_sk ? NULL : &dn_wild_sk;
- return &dn_sklist;
+ return &dn_sk_hash[scp->addrloc & DN_SK_HASH_MASK];
+}
+
+/*
+ * Valid ports are those greater than zero and not already in use.
+ */
+static int check_port(unsigned short port)
+{
+ struct sock *sk = dn_sk_hash[port & DN_SK_HASH_MASK];
+ if (port == 0)
+ return -1;
+ while(sk) {
+ struct dn_scp *scp = DN_SK(sk);
+ if (scp->addrloc == port)
+ return -1;
+ sk = sk->next;
+ }
+ return 0;
}
static unsigned short port_alloc(struct sock *sk)
{
struct dn_scp *scp = DN_SK(sk);
static unsigned short port = 0x2000;
+ unsigned short i_port = port;
- if (port == 0)
- port++;
+ while(check_port(++port) != 0) {
+ if (port == i_port)
+ return 0;
+ }
- scp->addrloc = port++;
+ scp->addrloc = port;
return 1;
}
@@ -238,6 +263,48 @@ static void dn_unhash_sock_bh(struct sock *sk)
sk->pprev = NULL;
}
+struct sock **listen_hash(struct sockaddr_dn *addr)
+{
+ int i;
+ unsigned hash = addr->sdn_objnum;
+
+ if (hash == 0) {
+ hash = addr->sdn_objnamel;
+ for(i = 0; i < addr->sdn_objnamel; i++) {
+ hash ^= addr->sdn_objname[i];
+ hash ^= (hash << 3);
+ }
+ }
+
+ return &dn_sk_hash[hash & DN_SK_HASH_MASK];
+}
+
+/*
+ * Called to transform a socket from bound (i.e. with a local address)
+ * into a listening socket (doesn't need a local port number) and rehashes
+ * based upon the object name/number.
+ */
+static void dn_rehash_sock(struct sock *sk)
+{
+ struct sock **skp = sk->pprev;
+ struct dn_scp *scp = DN_SK(sk);
+
+ if (scp->addr.sdn_flags & SDF_WILD)
+ return;
+
+ write_lock_bh(&dn_hash_lock);
+ while(*skp != sk)
+ skp = &((*skp)->next);
+ *skp = sk->next;
+
+ DN_SK(sk)->addrloc = 0;
+ skp = listen_hash(&DN_SK(sk)->addr);
+
+ sk->next = *skp;
+ sk->pprev = skp;
+ *skp = sk;
+ write_unlock_bh(&dn_hash_lock);
+}
int dn_sockaddr2username(struct sockaddr_dn *sdn, unsigned char *buf, unsigned char type)
{
@@ -328,10 +395,11 @@ int dn_username2sockaddr(unsigned char *data, int len, struct sockaddr_dn *sdn,
struct sock *dn_sklist_find_listener(struct sockaddr_dn *addr)
{
+ struct sock **skp = listen_hash(addr);
struct sock *sk;
read_lock(&dn_hash_lock);
- for(sk = dn_sklist; sk != NULL; sk = sk->next) {
+ for(sk = *skp; sk != NULL; sk = sk->next) {
struct dn_scp *scp = DN_SK(sk);
if (sk->state != TCP_LISTEN)
continue;
@@ -365,7 +433,8 @@ struct sock *dn_find_by_skb(struct sk_buff *skb)
struct dn_scp *scp;
read_lock(&dn_hash_lock);
- for(sk = dn_sklist; sk != NULL; sk = sk->next) {
+ sk = dn_sk_hash[cb->dst_port & DN_SK_HASH_MASK];
+ for (; sk != NULL; sk = sk->next) {
scp = DN_SK(sk);
if (cb->src != dn_saddr2dn(&scp->peer))
continue;
@@ -1045,6 +1114,9 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags)
sizeof(struct optdata_dn));
lock_sock(newsk);
+ /*
+ * FIXME: This can fail if we've run out of local ports....
+ */
dn_hash_sock(newsk);
dn_send_conn_ack(newsk);
@@ -1200,6 +1272,7 @@ static int dn_listen(struct socket *sock, int backlog)
sk->ack_backlog = 0;
sk->state = TCP_LISTEN;
err = 0;
+ dn_rehash_sock(sk);
out:
release_sock(sk);
@@ -2063,44 +2136,47 @@ static int dn_get_info(char *buffer, char **start, off_t offset, int length)
char buf2[DN_ASCBUF_LEN];
char local_object[DN_MAXOBJL+3];
char remote_object[DN_MAXOBJL+3];
+ int i;
len += sprintf(buffer + len, "Local Remote\n");
read_lock(&dn_hash_lock);
- for(sk = dn_sklist; sk != NULL; sk = sk->next) {
- scp = DN_SK(sk);
-
- dn_printable_object(&scp->addr, local_object);
- dn_printable_object(&scp->peer, remote_object);
-
- len += sprintf(buffer + len,
- "%6s/%04X %04d:%04d %04d:%04d %01d %-16s %6s/%04X %04d:%04d %04d:%04d %01d %-16s %4s %s\n",
- dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1),
- scp->addrloc,
- scp->numdat,
- scp->numoth,
- scp->ackxmt_dat,
- scp->ackxmt_oth,
- scp->flowloc_sw,
- local_object,
- dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2),
- scp->addrrem,
- scp->numdat_rcv,
- scp->numoth_rcv,
- scp->ackrcv_dat,
- scp->ackrcv_oth,
- scp->flowrem_sw,
- remote_object,
- dn_state2asc(scp->state),
- ((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER"));
-
- pos = begin + len;
- if (pos < offset) {
- len = 0;
- begin = pos;
+ for(i = 0; i < DN_SK_HASH_SIZE; i++) {
+ for(sk = dn_sk_hash[i]; sk != NULL; sk = sk->next) {
+ scp = DN_SK(sk);
+
+ dn_printable_object(&scp->addr, local_object);
+ dn_printable_object(&scp->peer, remote_object);
+
+ len += sprintf(buffer + len,
+ "%6s/%04X %04d:%04d %04d:%04d %01d %-16s %6s/%04X %04d:%04d %04d:%04d %01d %-16s %4s %s\n",
+ dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1),
+ scp->addrloc,
+ scp->numdat,
+ scp->numoth,
+ scp->ackxmt_dat,
+ scp->ackxmt_oth,
+ scp->flowloc_sw,
+ local_object,
+ dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2),
+ scp->addrrem,
+ scp->numdat_rcv,
+ scp->numoth_rcv,
+ scp->ackrcv_dat,
+ scp->ackrcv_oth,
+ scp->flowrem_sw,
+ remote_object,
+ dn_state2asc(scp->state),
+ ((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER"));
+
+ pos = begin + len;
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos > (offset + length))
+ break;
}
- if (pos > (offset + length))
- break;
}
read_unlock(&dn_hash_lock);
@@ -2158,7 +2234,7 @@ MODULE_PARM(addr, "2i");
MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node");
#endif
-static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.4.9s (C) 1995-2001 Linux DECnet Project Team\n";
+static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.4.15-pre5s (C) 1995-2001 Linux DECnet Project Team\n";
static int __init decnet_init(void)
{