#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>
#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)
{
/*
* 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;
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;
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;
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 */
* 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);
}
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);
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);
}
}
-char *dn_addr2asc(dn_address addr, char *buf)
+char *dn_addr2asc(__u16 addr, char *buf)
{
unsigned short node, area;
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)) {
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);
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;
/* 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);
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);
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;
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;
opt->opt_optl = *ptr++;
opt->opt_status = 0;
memcpy(opt->opt_data, ptr, opt->opt_optl);
- skb_pull(skb, opt->opt_optl + 1);
+ skb_pull(skb, dn_ntohs(opt->opt_optl) + 1);
}
skb = dn_wait_for_connect(sk, &timeo);
if (IS_ERR(skb)) {
release_sock(sk);
- return PTR_ERR(sk);
+ return PTR_ERR(skb);
}
}
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);
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);
/*
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;
{
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);
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:
}
}
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;
}
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))
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;
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);
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);
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);
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;
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);
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);
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;
}
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) {
goto out;
if (signal_pending(current)) {
- rv = -ERESTARTSYS;
+ rv = sock_intr_errno(timeo);
goto out;
}
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
/* 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);
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)
if (sk->sk_shutdown & SEND_SHUTDOWN) {
err = -EPIPE;
+ if (!(flags & MSG_NOSIGNAL))
+ send_sig(SIGPIPE, current, 0);
goto out_err;
}
goto out;
if (signal_pending(current)) {
- err = -ERESTARTSYS;
+ err = sock_intr_errno(timeo);
goto out;
}
/*
* 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;
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;
return sent ? sent : err;
out_err:
- err = dn_error(sk, flags, err);
+ err = sk_stream_error(sk, flags, err);
release_sock(sk);
return err;
}
.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),
.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,
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();
proc_net_fops_create("decnet", S_IRUGO, &dn_socket_seq_fops);
dn_register_sysctl();
-
- return 0;
+out:
+ return rc;
}
module_init(decnet_init);
proc_net_remove("decnet");
- kmem_cache_destroy(dn_sk_cachep);
+ proto_unregister(&dn_proto);
}
module_exit(decnet_exit);
#endif