/******************************************************************************
(c) 1995-1998 E.M. Serrat emserrat@geocities.com
-
+
This program 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
Version 0.0.1 2.0.30 01-dic-97 Eduardo Marcelo Serrat
(emserrat@geocities.com)
- First Development of DECnet Socket La-
+ First Development of DECnet Socket La-
yer for Linux. Only supports outgoing
connections.
Version 0.0.3 2.1.106 25-jun-98 Eduardo Marcelo Serrat
(emserrat@geocities.com)
_
- Added support for incoming connections
- so we can start developing server apps
- on Linux.
+ Added support for incoming connections
+ so we can start developing server apps
+ on Linux.
-
Module Support
Version 0.0.4 2.1.109 21-jul-98 Eduardo Marcelo Serrat
- (emserrat@geocities.com)
- _
- Added support for X11R6.4. Now we can
- use DECnet transport for X on Linux!!!
- -
+ (emserrat@geocities.com)
+ _
+ Added support for X11R6.4. Now we can
+ use DECnet transport for X on Linux!!!
+ -
Version 0.0.5 2.1.110 01-aug-98 Eduardo Marcelo Serrat
- (emserrat@geocities.com)
- Removed bugs on flow control
- Removed bugs on incoming accessdata
- order
- -
+ (emserrat@geocities.com)
+ Removed bugs on flow control
+ Removed bugs on incoming accessdata
+ order
+ -
Version 0.0.6 2.1.110 07-aug-98 Eduardo Marcelo Serrat
- dn_recvmsg fixes
+ dn_recvmsg fixes
- Patrick J. Caulfield
- dn_bind fixes
+ Patrick J. Caulfield
+ dn_bind fixes
*******************************************************************************/
#include <linux/module.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/poll.h>
+#include <net/net_namespace.h>
#include <net/neighbour.h>
#include <net/dst.h>
#include <net/fib_rules.h>
if (scp->addr.sdn_flags & SDF_WILD)
return hlist_empty(&dn_wild_sk) ? &dn_wild_sk : NULL;
- return &dn_sk_hash[scp->addrloc & DN_SK_HASH_MASK];
+ return &dn_sk_hash[dn_ntohs(scp->addrloc) & DN_SK_HASH_MASK];
}
-/*
+/*
* Valid ports are those greater than zero and not already in use.
*/
static int check_port(__le16 port)
if (port == 0)
return -1;
- sk_for_each(sk, node, &dn_sk_hash[port & DN_SK_HASH_MASK]) {
+ sk_for_each(sk, node, &dn_sk_hash[dn_ntohs(port) & DN_SK_HASH_MASK]) {
struct dn_scp *scp = DN_SK(sk);
if (scp->addrloc == port)
return -1;
static unsigned short port = 0x2000;
unsigned short i_port = port;
- while(check_port(++port) != 0) {
+ while(check_port(dn_htons(++port)) != 0) {
if (port == i_port)
return 0;
}
- scp->addrloc = port;
+ scp->addrloc = dn_htons(port);
return 1;
}
BUG_ON(sk_hashed(sk));
write_lock_bh(&dn_hash_lock);
-
+
if (!scp->addrloc && !port_alloc(sk))
goto out;
sk = sk_head(&dn_wild_sk);
if (sk) {
- if (sk->sk_state == TCP_LISTEN)
+ if (sk->sk_state == TCP_LISTEN)
sock_hold(sk);
else
sk = NULL;
struct dn_scp *scp;
read_lock(&dn_hash_lock);
- sk_for_each(sk, node, &dn_sk_hash[cb->dst_port & DN_SK_HASH_MASK]) {
+ sk_for_each(sk, node, &dn_sk_hash[dn_ntohs(cb->dst_port) & DN_SK_HASH_MASK]) {
scp = DN_SK(sk);
if (cb->src != dn_saddr2dn(&scp->peer))
continue;
static int dn_memory_pressure;
-static void dn_enter_memory_pressure(void)
+static void dn_enter_memory_pressure(struct sock *sk)
{
if (!dn_memory_pressure) {
dn_memory_pressure = 1;
.obj_size = sizeof(struct dn_sock),
};
-static struct sock *dn_alloc_sock(struct socket *sock, gfp_t gfp)
+static struct sock *dn_alloc_sock(struct net *net, struct socket *sock, gfp_t gfp)
{
struct dn_scp *scp;
- struct sock *sk = sk_alloc(PF_DECnet, gfp, &dn_proto, 1);
+ struct sock *sk = sk_alloc(net, PF_DECnet, gfp, &dn_proto);
if (!sk)
goto out;
scp->ackxmt_oth = 0; /* Last oth data ack'ed */
scp->ackrcv_dat = 0; /* Highest data ack recv*/
scp->ackrcv_oth = 0; /* Last oth data ack rec*/
- scp->flowrem_sw = DN_SEND;
+ scp->flowrem_sw = DN_SEND;
scp->flowloc_sw = DN_SEND;
scp->flowrem_dat = 0;
scp->flowrem_oth = 1;
-static int dn_create(struct socket *sock, int protocol)
+static int dn_create(struct net *net, struct socket *sock, int protocol)
{
struct sock *sk;
+ if (net != &init_net)
+ return -EAFNOSUPPORT;
+
switch(sock->type) {
case SOCK_SEQPACKET:
if (protocol != DNPROTO_NSP)
}
- if ((sk = dn_alloc_sock(sock, GFP_KERNEL)) == NULL)
+ if ((sk = dn_alloc_sock(net, sock, GFP_KERNEL)) == NULL)
return -ENOBUFS;
sk->sk_protocol = protocol;
sock_put(sk);
}
- return 0;
+ return 0;
}
static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct sock *sk = sock->sk;
struct dn_scp *scp = DN_SK(sk);
struct sockaddr_dn *saddr = (struct sockaddr_dn *)uaddr;
- struct net_device *dev;
+ struct net_device *dev, *ldev;
int rv;
if (addr_len != sizeof(struct sockaddr_dn))
if (!(saddr->sdn_flags & SDF_WILD)) {
if (dn_ntohs(saddr->sdn_nodeaddrl)) {
read_lock(&dev_base_lock);
- for(dev = dev_base; dev; dev = dev->next) {
+ ldev = NULL;
+ for_each_netdev(&init_net, dev) {
if (!dev->dn_ptr)
continue;
- if (dn_dev_islocal(dev, dn_saddr2dn(saddr)))
+ if (dn_dev_islocal(dev, dn_saddr2dn(saddr))) {
+ ldev = dev;
break;
+ }
}
read_unlock(&dev_base_lock);
- if (dev == NULL)
+ if (ldev == NULL)
return -EADDRNOTAVAIL;
}
}
}
release_sock(sk);
- return rv;
+ return rv;
}
*/
if ((scp->accessdata.acc_accl != 0) &&
(scp->accessdata.acc_accl <= 12)) {
-
+
scp->addr.sdn_objnamel = dn_htons(scp->accessdata.acc_accl);
memcpy(scp->addr.sdn_objname, scp->accessdata.acc_acc, dn_ntohs(scp->addr.sdn_objnamel));
static void dn_access_copy(struct sk_buff *skb, struct accessdata_dn *acc)
{
- unsigned char *ptr = skb->data;
+ unsigned char *ptr = skb->data;
- acc->acc_userl = *ptr++;
- memcpy(&acc->acc_user, ptr, acc->acc_userl);
- ptr += acc->acc_userl;
+ acc->acc_userl = *ptr++;
+ memcpy(&acc->acc_user, ptr, acc->acc_userl);
+ ptr += acc->acc_userl;
- acc->acc_passl = *ptr++;
- memcpy(&acc->acc_pass, ptr, acc->acc_passl);
- ptr += acc->acc_passl;
+ acc->acc_passl = *ptr++;
+ memcpy(&acc->acc_pass, ptr, acc->acc_passl);
+ ptr += acc->acc_passl;
- acc->acc_accl = *ptr++;
- memcpy(&acc->acc_acc, ptr, acc->acc_accl);
+ acc->acc_accl = *ptr++;
+ memcpy(&acc->acc_acc, ptr, acc->acc_accl);
- skb_pull(skb, acc->acc_accl + acc->acc_passl + acc->acc_userl + 3);
+ skb_pull(skb, acc->acc_accl + acc->acc_passl + acc->acc_userl + 3);
}
static void dn_user_copy(struct sk_buff *skb, struct optdata_dn *opt)
{
- unsigned char *ptr = skb->data;
-
- opt->opt_optl = *ptr++;
- opt->opt_status = 0;
- memcpy(opt->opt_data, ptr, opt->opt_optl);
- skb_pull(skb, dn_ntohs(opt->opt_optl) + 1);
-
+ unsigned char *ptr = skb->data;
+ u16 len = *ptr++; /* yes, it's 8bit on the wire */
+
+ BUG_ON(len > 16); /* we've checked the contents earlier */
+ opt->opt_optl = dn_htons(len);
+ opt->opt_status = 0;
+ memcpy(opt->opt_data, ptr, len);
+ skb_pull(skb, len + 1);
}
static struct sk_buff *dn_wait_for_connect(struct sock *sk, long *timeo)
lock_sock(sk);
- if (sk->sk_state != TCP_LISTEN || DN_SK(sk)->state != DN_O) {
+ if (sk->sk_state != TCP_LISTEN || DN_SK(sk)->state != DN_O) {
release_sock(sk);
return -EINVAL;
}
cb = DN_SKB_CB(skb);
sk->sk_ack_backlog--;
- newsk = dn_alloc_sock(newsock, sk->sk_allocation);
+ newsk = dn_alloc_sock(sock_net(sk), newsock, sk->sk_allocation);
if (newsk == NULL) {
release_sock(sk);
kfree_skb(skb);
dst_release(xchg(&newsk->sk_dst_cache, skb->dst));
skb->dst = NULL;
- DN_SK(newsk)->state = DN_CR;
+ DN_SK(newsk)->state = DN_CR;
DN_SK(newsk)->addrrem = cb->src_port;
DN_SK(newsk)->services_rem = cb->services;
DN_SK(newsk)->info_rem = cb->info;
DN_SK(newsk)->segsize_rem = cb->segsize;
DN_SK(newsk)->accept_mode = DN_SK(sk)->accept_mode;
-
+
if (DN_SK(newsk)->segsize_rem < 230)
DN_SK(newsk)->segsize_rem = 230;
dn_send_conn_ack(newsk);
/*
- * Here we use sk->sk_allocation since although the conn conf is
- * for the newsk, the context is the old socket.
- */
+ * Here we use sk->sk_allocation since although the conn conf is
+ * for the newsk, the context is the old socket.
+ */
if (DN_SK(newsk)->accept_mode == ACC_IMMED)
err = dn_confirm_accept(newsk, &timeo,
sk->sk_allocation);
}
release_sock(newsk);
- return err;
+ return err;
}
lock_sock(sk);
if (peer) {
- if ((sock->state != SS_CONNECTED &&
- sock->state != SS_CONNECTING) &&
+ if ((sock->state != SS_CONNECTED &&
+ sock->state != SS_CONNECTING) &&
scp->accept_mode == ACC_IMMED) {
- release_sock(sk);
+ release_sock(sk);
return -ENOTCONN;
}
release_sock(sk);
- return 0;
+ return 0;
}
out:
release_sock(sk);
- return err;
+ return err;
}
return err;
}
-static int __dn_setsockopt(struct socket *sock, int level,int optname, char __user *optval, int optlen, int flags)
+static int __dn_setsockopt(struct socket *sock, int level,int optname, char __user *optval, int optlen, int flags)
{
struct sock *sk = sock->sk;
struct dn_scp *scp = DN_SK(sk);
switch(optname) {
case DSO_CONDATA:
- if (sock->state == SS_CONNECTED)
+ if (sock->state == SS_CONNECTED)
return -EISCONN;
if ((scp->state != DN_O) && (scp->state != DN_CR))
return -EINVAL;
break;
case DSO_DISDATA:
- if (sock->state != SS_CONNECTED && scp->accept_mode == ACC_IMMED)
+ if (sock->state != SS_CONNECTED && scp->accept_mode == ACC_IMMED)
return -ENOTCONN;
if (optlen != sizeof(struct optdata_dn))
break;
case DSO_CONACCESS:
- if (sock->state == SS_CONNECTED)
+ if (sock->state == SS_CONNECTED)
return -EISCONN;
if (scp->state != DN_O)
return -EINVAL;
if(get_user(r_len , optlen))
return -EFAULT;
-
+
switch(optname) {
case DSO_CONDATA:
if (r_len > sizeof(struct optdata_dn))
#ifdef CONFIG_NETFILTER
{
int val, len;
-
+
if(get_user(len, optlen))
return -EFAULT;
-
- val = nf_getsockopt(sk, PF_DECnet, optname,
+
+ val = nf_getsockopt(sk, PF_DECnet, optname,
optval, &len);
if (val >= 0)
val = put_user(len, optlen);
case DSO_SEQPACKET:
case DSO_CONACCEPT:
case DSO_CONREJECT:
- return -ENOPROTOOPT;
+ return -ENOPROTOOPT;
case DSO_MAXWINDOW:
if (r_len > sizeof(unsigned long))
* See if there is data ready to read, sleep if there isn't
*/
for(;;) {
+ DEFINE_WAIT(wait);
+
if (sk->sk_err)
goto out;
}
}
}
-
+
if (scp->state != DN_RUN)
goto out;
goto out;
}
- set_bit(SOCK_ASYNC_WAITDATA, &sock->flags);
- SOCK_SLEEP_PRE(sk)
-
- if (!dn_data_ready(sk, queue, flags, target))
- schedule();
-
- SOCK_SLEEP_POST(sk)
- clear_bit(SOCK_ASYNC_WAITDATA, &sock->flags);
+ prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+ set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ sk_wait_event(sk, &timeo, dn_data_ready(sk, queue, flags, target));
+ clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ finish_wait(sk->sk_sleep, &wait);
}
for(skb = queue->next; skb != (struct sk_buff *)queue; skb = nskb) {
if (skb->len == 0) {
skb_unlink(skb, queue);
kfree_skb(skb);
- /*
+ /*
* N.B. Don't refer to skb or cb after this point
* in loop.
*/
}
}
- if (eor) {
+ if (eor) {
if (sk->sk_type == SOCK_SEQPACKET)
break;
if (!(flags & MSG_WAITALL))
}
/*
- * The DECnet spec requires the the "routing layer" accepts packets which
+ * The DECnet spec requires that the "routing layer" accepts packets which
* are at least 230 bytes in size. This excludes any headers which the NSP
* layer might add, so we always assume that we'll be using the maximal
* length header on data packets. The variation in length is due to the
return mss_now;
}
-/*
+/*
* N.B. We get the timeout wrong here, but then we always did get it
* wrong before and this is another step along the road to correcting
* it. It ought to get updated each time we pass through the routine,
struct sk_buff *skb = sock_alloc_send_skb(sk, datalen,
noblock, errcode);
if (skb) {
- skb->protocol = __constant_htons(ETH_P_DNA_RT);
+ skb->protocol = htons(ETH_P_DNA_RT);
skb->pkt_type = PACKET_OUTGOING;
}
return skb;
* size.
*/
if (dn_queue_too_long(scp, queue, flags)) {
+ DEFINE_WAIT(wait);
+
if (flags & MSG_DONTWAIT) {
err = -EWOULDBLOCK;
goto out;
}
- SOCK_SLEEP_PRE(sk)
-
- if (dn_queue_too_long(scp, queue, flags))
- schedule();
-
- SOCK_SLEEP_POST(sk)
-
+ prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+ set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ sk_wait_event(sk, &timeo,
+ !dn_queue_too_long(scp, queue, flags));
+ clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ finish_wait(sk->sk_sleep, &wait);
continue;
}
cb->nsp_flags |= 0x20;
scp->seg_total += len;
-
+
if (((sent + len) == size) && (flags & MSG_EOR)) {
cb->nsp_flags |= 0x40;
scp->seg_total = 0;
{
struct net_device *dev = (struct net_device *)ptr;
+ if (!net_eq(dev_net(dev), &init_net))
+ return NOTIFY_DONE;
+
switch(event) {
case NETDEV_UP:
dn_dev_up(dev);
static void dn_printable_object(struct sockaddr_dn *dn, unsigned char *buf)
{
int i;
-
+
switch (dn_ntohs(dn->sdn_objnamel)) {
case 0:
sprintf(buf, "%d", dn->sdn_objnum);
buf[i] = '.';
}
buf[i] = 0;
- }
+ }
}
static char *dn_state2asc(unsigned char state)
return 0;
}
-static struct seq_operations dn_socket_seq_ops = {
+static const struct seq_operations dn_socket_seq_ops = {
.start = dn_socket_seq_start,
.next = dn_socket_seq_next,
.stop = dn_socket_seq_stop,
static int dn_socket_seq_open(struct inode *inode, struct file *file)
{
- struct seq_file *seq;
- int rc = -ENOMEM;
- struct dn_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
-
- if (!s)
- goto out;
-
- rc = seq_open(file, &dn_socket_seq_ops);
- if (rc)
- goto out_kfree;
-
- seq = file->private_data;
- seq->private = s;
- memset(s, 0, sizeof(*s));
-out:
- return rc;
-out_kfree:
- kfree(s);
- goto out;
+ return seq_open_private(file, &dn_socket_seq_ops,
+ sizeof(struct dn_iter_state));
}
-static struct file_operations dn_socket_seq_fops = {
+static const struct file_operations dn_socket_seq_fops = {
.owner = THIS_MODULE,
.open = dn_socket_seq_open,
.read = seq_read,
{
int rc;
- printk(banner);
+ printk(banner);
rc = proto_register(&dn_proto, 1);
if (rc != 0)
dev_add_pack(&dn_dix_packet_type);
register_netdevice_notifier(&dn_dev_notifier);
- proc_net_fops_create("decnet", S_IRUGO, &dn_socket_seq_fops);
+ proc_net_fops_create(&init_net, "decnet", S_IRUGO, &dn_socket_seq_fops);
dn_register_sysctl();
out:
return rc;
static void __exit decnet_exit(void)
{
sock_unregister(AF_DECnet);
+ rtnl_unregister_all(PF_DECnet);
dev_remove_pack(&dn_dix_packet_type);
dn_unregister_sysctl();
dn_neigh_cleanup();
dn_fib_cleanup();
- proc_net_remove("decnet");
+ proc_net_remove(&init_net, "decnet");
proto_unregister(&dn_proto);
}