fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / net / decnet / af_decnet.c
index e0d5284..21f20f2 100644 (file)
@@ -99,7 +99,6 @@ Version 0.0.6    2.1.110   07-aug-98   Eduardo Marcelo Serrat
                                        dn_bind fixes
 *******************************************************************************/
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/types.h>
@@ -118,10 +117,11 @@ Version 0.0.6    2.1.110   07-aug-98   Eduardo Marcelo Serrat
 #include <linux/netfilter.h>
 #include <linux/seq_file.h>
 #include <net/sock.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <net/flow.h>
 #include <asm/system.h>
 #include <asm/ioctls.h>
+#include <linux/capability.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/proc_fs.h>
@@ -130,6 +130,7 @@ Version 0.0.6    2.1.110   07-aug-98   Eduardo Marcelo Serrat
 #include <linux/poll.h>
 #include <net/neighbour.h>
 #include <net/dst.h>
+#include <net/fib_rules.h>
 #include <net/dn.h>
 #include <net/dn_nsp.h>
 #include <net/dn_dev.h>
@@ -149,14 +150,14 @@ static void dn_keepalive(struct sock *sk);
 #define DN_SK_HASH_MASK (DN_SK_HASH_SIZE - 1)
 
 
-static kmem_cache_t *dn_sk_cachep;
-static struct proto_ops dn_proto_ops;
-static rwlock_t dn_hash_lock = RW_LOCK_UNLOCKED;
+static const struct proto_ops dn_proto_ops;
+static DEFINE_RWLOCK(dn_hash_lock);
 static struct hlist_head dn_sk_hash[DN_SK_HASH_SIZE];
 static struct hlist_head dn_wild_sk;
+static atomic_t decnet_memory_allocated;
 
-static int __dn_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen, int flags);
-static int __dn_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen, int flags);
+static int __dn_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen, int flags);
+static int __dn_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen, int flags);
 
 static struct hlist_head *dn_find_list(struct sock *sk)
 {
@@ -165,13 +166,13 @@ static struct hlist_head *dn_find_list(struct sock *sk)
        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(unsigned short port)
+static int check_port(__le16 port)
 {
        struct sock *sk;
        struct hlist_node *node;
@@ -179,7 +180,7 @@ static int check_port(unsigned short 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;
@@ -193,12 +194,12 @@ static unsigned short port_alloc(struct sock *sk)
 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;
 }
@@ -246,7 +247,7 @@ static void dn_unhash_sock_bh(struct sock *sk)
        write_unlock_bh(&dn_hash_lock);
 }
 
-struct hlist_head *listen_hash(struct sockaddr_dn *addr)
+static struct hlist_head *listen_hash(struct sockaddr_dn *addr)
 {
        int i;
        unsigned hash = addr->sdn_objnum;
@@ -417,7 +418,7 @@ struct sock *dn_find_by_skb(struct sk_buff *skb)
        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;
@@ -447,21 +448,39 @@ static void dn_destruct(struct sock *sk)
        dst_release(xchg(&sk->sk_dst_cache, NULL));
 }
 
-struct sock *dn_alloc_sock(struct socket *sock, int gfp)
+static int dn_memory_pressure;
+
+static void dn_enter_memory_pressure(void)
+{
+       if (!dn_memory_pressure) {
+               dn_memory_pressure = 1;
+       }
+}
+
+static struct proto dn_proto = {
+       .name                   = "NSP",
+       .owner                  = THIS_MODULE,
+       .enter_memory_pressure  = dn_enter_memory_pressure,
+       .memory_pressure        = &dn_memory_pressure,
+       .memory_allocated       = &decnet_memory_allocated,
+       .sysctl_mem             = sysctl_decnet_mem,
+       .sysctl_wmem            = sysctl_decnet_wmem,
+       .sysctl_rmem            = sysctl_decnet_rmem,
+       .max_header             = DN_MAX_NSP_DATA_HEADER + 64,
+       .obj_size               = sizeof(struct dn_sock),
+};
+
+static struct sock *dn_alloc_sock(struct socket *sock, gfp_t gfp)
 {
        struct dn_scp *scp;
-       struct sock *sk = sk_alloc(PF_DECnet, gfp, sizeof(struct dn_sock),
-                                  dn_sk_cachep);
+       struct sock *sk = sk_alloc(PF_DECnet, gfp, &dn_proto, 1);
 
        if  (!sk)
                goto out;
 
-       sk->sk_protinfo = scp = (struct dn_scp *)(sk + 1);
-
        if (sock)
                sock->ops = &dn_proto_ops;
        sock_init_data(sock, sk);
-       sk_set_owner(sk, THIS_MODULE);
 
        sk->sk_backlog_rcv = dn_nsp_backlog_rcv;
        sk->sk_destruct    = dn_destruct;
@@ -469,8 +488,11 @@ struct sock *dn_alloc_sock(struct socket *sock, int gfp)
        sk->sk_family      = PF_DECnet;
        sk->sk_protocol    = 0;
        sk->sk_allocation  = gfp;
+       sk->sk_sndbuf      = sysctl_decnet_wmem[1];
+       sk->sk_rcvbuf      = sysctl_decnet_rmem[1];
 
        /* Initialization of DECnet Session Control Port                */
+       scp = DN_SK(sk);
        scp->state      = DN_O;         /* Open                 */
        scp->numdat     = 1;            /* Next data seg to tx  */
        scp->numoth     = 1;            /* Next oth data to tx  */
@@ -534,7 +556,7 @@ static void dn_keepalive(struct sock *sk)
         * we are double checking that we are not sending too
         * many of these keepalive frames.
         */
-       if (skb_queue_len(&scp->other_xmit_queue) == 0)
+       if (skb_queue_empty(&scp->other_xmit_queue))
                dn_nsp_send_link(sk, DN_NOCHANGE, 0);
 }
 
@@ -578,7 +600,6 @@ int dn_destroy_timer(struct sock *sk)
        if (sk->sk_socket)
                return 0;
 
-       dn_stop_fast_timer(sk); /* unlikely, but possible that this is runninng */
        if ((jiffies - scp->stamp) >= (HZ * decnet_time_wait)) {
                dn_unhash_sock(sk);
                sock_put(sk);
@@ -631,7 +652,6 @@ disc_reject:
                default:
                        printk(KERN_DEBUG "DECnet: dn_destroy_sock passed socket in invalid state\n");
                case DN_O:
-                       dn_stop_fast_timer(sk);
                        dn_stop_slow_timer(sk);
 
                        dn_unhash_sock_bh(sk);
@@ -641,7 +661,7 @@ disc_reject:
        }
 }
 
-char *dn_addr2asc(dn_address addr, char *buf)
+char *dn_addr2asc(__u16 addr, char *buf)
 {
        unsigned short node, area;
 
@@ -719,22 +739,9 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        if (saddr->sdn_flags & ~SDF_WILD)
                return -EINVAL;
 
-#if 1
        if (!capable(CAP_NET_BIND_SERVICE) && (saddr->sdn_objnum ||
            (saddr->sdn_flags & SDF_WILD)))
                return -EACCES;
-#else
-       /*
-        * Maybe put the default actions in the default security ops for
-        * dn_prot_sock ? Would be nice if the capable call would go there
-        * too.
-        */
-       if (security_dn_prot_sock(saddr) &&
-           !capable(CAP_NET_BIND_SERVICE) || 
-           saddr->sdn_objnum || (saddr->sdn_flags & SDF_WILD))
-               return -EACCES;
-#endif
-
 
        if (!(saddr->sdn_flags & SDF_WILD)) {
                if (dn_ntohs(saddr->sdn_nodeaddrl)) {
@@ -753,14 +760,13 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 
        rv = -EINVAL;
        lock_sock(sk);
-       if (sk->sk_zapped) {
+       if (sock_flag(sk, SOCK_ZAPPED)) {
                memcpy(&scp->addr, saddr, addr_len);
-               sk->sk_zapped = 0;
+               sock_reset_flag(sk, SOCK_ZAPPED);
 
                rv = dn_hash_sock(sk);
-               if (rv) {
-                       sk->sk_zapped = 1;
-               }
+               if (rv)
+                       sock_set_flag(sk, SOCK_ZAPPED);
        }
        release_sock(sk);
 
@@ -774,7 +780,7 @@ static int dn_auto_bind(struct socket *sock)
        struct dn_scp *scp = DN_SK(sk);
        int rv;
 
-       sk->sk_zapped = 0;
+       sock_reset_flag(sk, SOCK_ZAPPED);
 
        scp->addr.sdn_flags  = 0;
        scp->addr.sdn_objnum = 0;
@@ -795,18 +801,17 @@ static int dn_auto_bind(struct socket *sock)
        /* End of compatibility stuff */
 
        scp->addr.sdn_add.a_len = dn_htons(2);
-       rv = dn_dev_bind_default((dn_address *)scp->addr.sdn_add.a_addr);
+       rv = dn_dev_bind_default((__le16 *)scp->addr.sdn_add.a_addr);
        if (rv == 0) {
                rv = dn_hash_sock(sk);
-               if (rv) {
-                       sk->sk_zapped = 1;
-               }
+               if (rv)
+                       sock_set_flag(sk, SOCK_ZAPPED);
        }
 
        return rv;
 }
 
-static int dn_confirm_accept(struct sock *sk, long *timeo, int allocation)
+static int dn_confirm_accept(struct sock *sk, long *timeo, gfp_t allocation)
 {
        struct dn_scp *scp = DN_SK(sk);
        DEFINE_WAIT(wait);
@@ -816,7 +821,7 @@ static int dn_confirm_accept(struct sock *sk, long *timeo, int allocation)
                return -EINVAL;
 
        scp->state = DN_CC;
-       scp->segsize_loc = dst_path_metric(__sk_dst_get(sk), RTAX_ADVMSS);
+       scp->segsize_loc = dst_metric(__sk_dst_get(sk), RTAX_ADVMSS);
        dn_send_conn_conf(sk, allocation);
 
        prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
@@ -925,7 +930,7 @@ static int __dn_connect(struct sock *sk, struct sockaddr_dn *addr, int addrlen,
        if (addr->sdn_flags & SDF_WILD)
                goto out;
 
-       if (sk->sk_zapped) {
+       if (sock_flag(sk, SOCK_ZAPPED)) {
                err = dn_auto_bind(sk->sk_socket);
                if (err)
                        goto out;
@@ -945,7 +950,7 @@ static int __dn_connect(struct sock *sk, struct sockaddr_dn *addr, int addrlen,
        sk->sk_route_caps = sk->sk_dst_cache->dev->features;
        sock->state = SS_CONNECTING;
        scp->state = DN_CI;
-       scp->segsize_loc = dst_path_metric(sk->sk_dst_cache, RTAX_ADVMSS);
+       scp->segsize_loc = dst_metric(sk->sk_dst_cache, RTAX_ADVMSS);
 
        dn_nsp_send_conninit(sk, NSP_CI);
        err = -EINPROGRESS;
@@ -1011,13 +1016,14 @@ static void dn_access_copy(struct sk_buff *skb, struct accessdata_dn *acc)
 
 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, 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)
@@ -1075,7 +1081,7 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags)
                skb = dn_wait_for_connect(sk, &timeo);
                if (IS_ERR(skb)) {
                        release_sock(sk);
-                       return PTR_ERR(sk);
+                       return PTR_ERR(skb);
                }
        }
 
@@ -1116,8 +1122,8 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags)
 
        skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &(DN_SK(newsk)->addr), &type));
        skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &(DN_SK(newsk)->peer), &type));
-       *(dn_address *)(DN_SK(newsk)->peer.sdn_add.a_addr) = cb->src;
-       *(dn_address *)(DN_SK(newsk)->addr.sdn_add.a_addr) = cb->dst;
+       *(__le16 *)(DN_SK(newsk)->peer.sdn_add.a_addr) = cb->src;
+       *(__le16 *)(DN_SK(newsk)->addr.sdn_add.a_addr) = cb->dst;
 
        menuver = *skb->data;
        skb_pull(skb, 1);
@@ -1144,7 +1150,7 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags)
        lock_sock(newsk);
        err = dn_hash_sock(newsk);
        if (err == 0) {
-               newsk->sk_zapped = 0;
+               sock_reset_flag(newsk, SOCK_ZAPPED);
                dn_send_conn_ack(newsk);
 
                /*
@@ -1173,8 +1179,10 @@ static int dn_getname(struct socket *sock, struct sockaddr *uaddr,int *uaddr_len
        if (peer) {
                if ((sock->state != SS_CONNECTED && 
                     sock->state != SS_CONNECTING) && 
-                   scp->accept_mode == ACC_IMMED)
+                   scp->accept_mode == ACC_IMMED) {
+                       release_sock(sk);
                        return -ENOTCONN;
+               }
 
                memcpy(sa, &scp->peer, sizeof(struct sockaddr_dn));
        } else {
@@ -1193,7 +1201,7 @@ static unsigned int dn_poll(struct file *file, struct socket *sock, poll_table
        struct dn_scp *scp = DN_SK(sk);
        int mask = datagram_poll(file, sock, wait);
 
-       if (skb_queue_len(&scp->other_receive_queue))
+       if (!skb_queue_empty(&scp->other_receive_queue))
                mask |= POLLRDBAND;
 
        return mask;
@@ -1212,11 +1220,11 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
        {
        case SIOCGIFADDR:
        case SIOCSIFADDR:
-               return dn_dev_ioctl(cmd, (void *)arg);
+               return dn_dev_ioctl(cmd, (void __user *)arg);
 
        case SIOCATMARK:
                lock_sock(sk);
-               val = (skb_queue_len(&scp->other_receive_queue) != 0);
+               val = !skb_queue_empty(&scp->other_receive_queue);
                if (scp->state != DN_RUN)
                        val = -ENOTCONN;
                release_sock(sk);
@@ -1226,7 +1234,7 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
                if (amount < 0)
                        amount = 0;
-               err = put_user(amount, (int *)arg);
+               err = put_user(amount, (int __user *)arg);
                break;
 
        case TIOCINQ:
@@ -1244,11 +1252,11 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                        }
                }
                release_sock(sk);
-               err = put_user(amount, (int *)arg);
+               err = put_user(amount, (int __user *)arg);
                break;
 
        default:
-               err = dev_ioctl(cmd, (void *)arg);
+               err = -ENOIOCTLCMD;
                break;
        }
 
@@ -1262,7 +1270,7 @@ static int dn_listen(struct socket *sock, int backlog)
 
        lock_sock(sk);
 
-       if (sk->sk_zapped)
+       if (sock_flag(sk, SOCK_ZAPPED))
                goto out;
 
        if ((DN_SK(sk)->state != DN_O) || (sk->sk_state == TCP_LISTEN))
@@ -1313,7 +1321,7 @@ out:
        return err;
 }
 
-static int dn_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
+static int dn_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
 {
        struct sock *sk = sock->sk;
        int err;
@@ -1325,7 +1333,7 @@ static int dn_setsockopt(struct socket *sock, int level, int optname, char *optv
        return err;
 }
 
-static int __dn_setsockopt(struct socket *sock, int level,int optname, char *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);
@@ -1360,7 +1368,7 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char *opt
                        if (optlen != sizeof(struct optdata_dn))
                                return -EINVAL;
 
-                       if (u.opt.opt_optl > 16)
+                       if (dn_ntohs(u.opt.opt_optl) > 16)
                                return -EINVAL;
 
                        memcpy(&scp->conndata_out, &u.opt, optlen);
@@ -1373,7 +1381,7 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char *opt
                        if (optlen != sizeof(struct optdata_dn))
                                return -EINVAL;
 
-                       if (u.opt.opt_optl > 16)
+                       if (dn_ntohs(u.opt.opt_optl) > 16)
                                return -EINVAL;
 
                        memcpy(&scp->discdata_out, &u.opt, optlen);
@@ -1490,7 +1498,7 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char *opt
        return 0;
 }
 
-static int dn_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
+static int dn_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
 {
        struct sock *sk = sock->sk;
        int err;
@@ -1502,7 +1510,7 @@ static int dn_getsockopt(struct socket *sock, int level, int optname, char *optv
        return err;
 }
 
-static int __dn_getsockopt(struct socket *sock, int level,int optname, char *optval,int *optlen, int flags)
+static int __dn_getsockopt(struct socket *sock, int level,int optname, char __user *optval,int __user *optlen, int flags)
 {
        struct  sock *sk = sock->sk;
        struct dn_scp *scp = DN_SK(sk);
@@ -1632,7 +1640,7 @@ static int dn_data_ready(struct sock *sk, struct sk_buff_head *q, int flags, int
        int len = 0;
 
        if (flags & MSG_OOB)
-               return skb_queue_len(q) ? 1 : 0;
+               return !skb_queue_empty(q) ? 1 : 0;
 
        while(skb != (struct sk_buff *)q) {
                struct dn_skb_cb *cb = DN_SKB_CB(skb);
@@ -1674,23 +1682,21 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock,
 
        lock_sock(sk);
 
-       if (sk->sk_zapped) {
+       if (sock_flag(sk, SOCK_ZAPPED)) {
                rv = -EADDRNOTAVAIL;
                goto out;
        }
 
-       rv = dn_check_state(sk, NULL, 0, &timeo, flags);
-       if (rv)
-               goto out;
-
        if (sk->sk_shutdown & RCV_SHUTDOWN) {
-               if (!(flags & MSG_NOSIGNAL))
-                       send_sig(SIGPIPE, current, 0);
-               rv = -EPIPE;
+               rv = 0;
                goto out;
        }
 
-       if (flags & ~(MSG_PEEK|MSG_OOB|MSG_WAITALL|MSG_DONTWAIT|MSG_NOSIGNAL)) {
+       rv = dn_check_state(sk, NULL, 0, &timeo, flags);
+       if (rv)
+               goto out;
+
+       if (flags & ~(MSG_CMSG_COMPAT|MSG_PEEK|MSG_OOB|MSG_WAITALL|MSG_DONTWAIT|MSG_NOSIGNAL)) {
                rv = -EOPNOTSUPP;
                goto out;
        }
@@ -1709,7 +1715,7 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock,
                if (sk->sk_err)
                        goto out;
 
-               if (skb_queue_len(&scp->other_receive_queue)) {
+               if (!skb_queue_empty(&scp->other_receive_queue)) {
                        if (!(flags & MSG_OOB)) {
                                msg->msg_flags |= MSG_OOB;
                                if (!scp->other_report) {
@@ -1723,7 +1729,7 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock,
                        goto out;
 
                if (signal_pending(current)) {
-                       rv = -ERESTARTSYS;
+                       rv = sock_intr_errno(timeo);
                        goto out;
                }
 
@@ -1765,7 +1771,7 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock,
                nskb = skb->next;
 
                if (skb->len == 0) {
-                       skb_unlink(skb);
+                       skb_unlink(skb, queue);
                        kfree_skb(skb);
                        /* 
                         * N.B. Don't refer to skb or cb after this point
@@ -1871,24 +1877,34 @@ static inline unsigned int dn_current_mss(struct sock *sk, int flags)
 
        /* This works out the maximum size of segment we can send out */
        if (dst) {
-               u32 mtu = dst_pmtu(dst);
+               u32 mtu = dst_mtu(dst);
                mss_now = min_t(int, dn_mss_from_pmtu(dst->dev, mtu), mss_now);
        }
 
        return mss_now;
 }
 
-static int dn_error(struct sock *sk, int flags, int err)
+/* 
+ * 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,
+ * but in practise it probably doesn't matter too much for now.
+ */
+static inline struct sk_buff *dn_alloc_send_pskb(struct sock *sk,
+                             unsigned long datalen, int noblock,
+                             int *errcode)
 {
-       if (err == -EPIPE)
-               err = sock_error(sk) ? : -EPIPE;
-       if (err == -EPIPE && !(flags & MSG_NOSIGNAL))
-               send_sig(SIGPIPE, current, 0);
-       return err;
+       struct sk_buff *skb = sock_alloc_send_skb(sk, datalen,
+                                                  noblock, errcode);
+       if (skb) {
+               skb->protocol = __constant_htons(ETH_P_DNA_RT);
+               skb->pkt_type = PACKET_OUTGOING;
+       }
+       return skb;
 }
 
 static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
-          struct msghdr *msg, size_t size)
+                     struct msghdr *msg, size_t size)
 {
        struct sock *sk = sock->sk;
        struct dn_scp *scp = DN_SK(sk);
@@ -1903,26 +1919,29 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
        struct dn_skb_cb *cb;
        size_t len;
        unsigned char fctype;
-       long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
+       long timeo;
 
-       if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|MSG_MORE))
+       if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|MSG_MORE|MSG_CMSG_COMPAT))
                return -EOPNOTSUPP;
 
        if (addr_len && (addr_len != sizeof(struct sockaddr_dn)))
                return -EINVAL;
 
+       lock_sock(sk);
+       timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
        /*
         * The only difference between stream sockets and sequenced packet
         * sockets is that the stream sockets always behave as if MSG_EOR
         * has been set.
         */
        if (sock->type == SOCK_STREAM) {
-               if (flags & MSG_EOR)
-                       return -EINVAL;
+               if (flags & MSG_EOR) {
+                       err = -EINVAL;
+                       goto out;
+               }
                flags |= MSG_EOR;
        }
 
-       lock_sock(sk);
 
        err = dn_check_state(sk, addr, addr_len, &timeo, flags);
        if (err)
@@ -1930,6 +1949,8 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
 
        if (sk->sk_shutdown & SEND_SHUTDOWN) {
                err = -EPIPE;
+               if (!(flags & MSG_NOSIGNAL))
+                       send_sig(SIGPIPE, current, 0);
                goto out_err;
        }
 
@@ -1957,7 +1978,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
                        goto out;
 
                if (signal_pending(current)) {
-                       err = -ERESTARTSYS;
+                       err = sock_intr_errno(timeo);
                        goto out;
                }
 
@@ -1991,8 +2012,12 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
 
                /*
                 * Get a suitably sized skb.
+                * 64 is a bit of a hack really, but its larger than any
+                * link-layer headers and has served us well as a good
+                * guess as to their real length.
                 */
-               skb = dn_alloc_send_skb(sk, &len, flags & MSG_DONTWAIT, &err);
+               skb = dn_alloc_send_pskb(sk, len + 64 + DN_MAX_NSP_DATA_HEADER,
+                                        flags & MSG_DONTWAIT, &err);
 
                if (err)
                        break;
@@ -2002,7 +2027,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
 
                cb = DN_SKB_CB(skb);
 
-               skb_reserve(skb, DN_MAX_NSP_DATA_HEADER);
+               skb_reserve(skb, 64 + DN_MAX_NSP_DATA_HEADER);
 
                if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
                        err = -EFAULT;
@@ -2047,7 +2072,7 @@ out:
        return sent ? sent : err;
 
 out_err:
-       err = dn_error(sk, flags, err);
+       err = sk_stream_error(sk, flags, err);
        release_sock(sk);
        return err;
 }
@@ -2075,7 +2100,7 @@ static struct notifier_block dn_dev_notifier = {
        .notifier_call = dn_device_event,
 };
 
-extern int dn_route_rcv(struct sk_buff *, struct net_device *, struct packet_type *);
+extern int dn_route_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
 
 static struct packet_type dn_dix_packet_type = {
        .type =         __constant_htons(ETH_P_DNA_RT),
@@ -2321,7 +2346,7 @@ static struct net_proto_family    dn_family_ops = {
        .owner  =       THIS_MODULE,
 };
 
-static struct proto_ops dn_proto_ops = {
+static const struct proto_ops dn_proto_ops = {
        .family =       AF_DECnet,
        .owner =        THIS_MODULE,
        .release =      dn_release,
@@ -2354,14 +2379,13 @@ static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.5.68s (
 
 static int __init decnet_init(void)
 {
+       int rc;
+
         printk(banner);
 
-       dn_sk_cachep = kmem_cache_create("decnet_socket_cache",
-                                        sizeof(struct dn_sock),
-                                        0, SLAB_HWCACHE_ALIGN,
-                                        NULL, NULL);
-       if (!dn_sk_cachep)
-               return -ENOMEM;
+       rc = proto_register(&dn_proto, 1);
+       if (rc != 0)
+               goto out;
 
        dn_neigh_init();
        dn_dev_init();
@@ -2374,8 +2398,8 @@ static int __init decnet_init(void)
 
        proc_net_fops_create("decnet", S_IRUGO, &dn_socket_seq_fops);
        dn_register_sysctl();
-
-       return 0;
+out:
+       return rc;
 
 }
 module_init(decnet_init);
@@ -2402,7 +2426,7 @@ static void __exit decnet_exit(void)
 
        proc_net_remove("decnet");
 
-       kmem_cache_destroy(dn_sk_cachep);
+       proto_unregister(&dn_proto);
 }
 module_exit(decnet_exit);
 #endif