patch-2.4.17 linux/net/decnet/af_decnet.c
Next file: linux/net/decnet/dn_dev.c
Previous file: linux/net/decnet/README
Back to the patch index
Back to the overall index
- Lines: 246
- Date:
Fri Dec 21 16:40:33 2001
- Orig file:
linux-2.4.16/net/decnet/af_decnet.c
- Orig date:
Fri Nov 9 22:12:54 2001
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/net/decnet/af_decnet.c linux/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 @@
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 @@
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 @@
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 @@
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 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 @@
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 @@
sk->ack_backlog = 0;
sk->state = TCP_LISTEN;
err = 0;
+ dn_rehash_sock(sk);
out:
release_sock(sk);
@@ -2063,44 +2136,47 @@
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_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)
{
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)