x25: use limited socket backlog
[safe/jmp/linux-2.6] / net / x25 / af_x25.c
index ebbfe6b..9796f3e 100644 (file)
@@ -55,6 +55,7 @@
 #include <linux/notifier.h>
 #include <linux/init.h>
 #include <linux/compat.h>
+#include <linux/ctype.h>
 
 #include <net/x25.h>
 #include <net/compat.h>
@@ -415,6 +416,7 @@ static int x25_setsockopt(struct socket *sock, int level, int optname,
        struct sock *sk = sock->sk;
        int rc = -ENOPROTOOPT;
 
+       lock_kernel();
        if (level != SOL_X25 || optname != X25_QBITINCL)
                goto out;
 
@@ -429,6 +431,7 @@ static int x25_setsockopt(struct socket *sock, int level, int optname,
        x25_sk(sk)->qbitincl = !!opt;
        rc = 0;
 out:
+       unlock_kernel();
        return rc;
 }
 
@@ -438,6 +441,7 @@ static int x25_getsockopt(struct socket *sock, int level, int optname,
        struct sock *sk = sock->sk;
        int val, len, rc = -ENOPROTOOPT;
 
+       lock_kernel();
        if (level != SOL_X25 || optname != X25_QBITINCL)
                goto out;
 
@@ -458,6 +462,7 @@ static int x25_getsockopt(struct socket *sock, int level, int optname,
        val = x25_sk(sk)->qbitincl;
        rc = copy_to_user(optval, &val, len) ? -EFAULT : 0;
 out:
+       unlock_kernel();
        return rc;
 }
 
@@ -466,12 +471,14 @@ static int x25_listen(struct socket *sock, int backlog)
        struct sock *sk = sock->sk;
        int rc = -EOPNOTSUPP;
 
+       lock_kernel();
        if (sk->sk_state != TCP_LISTEN) {
                memset(&x25_sk(sk)->dest_addr, 0, X25_ADDR_LEN);
                sk->sk_max_ack_backlog = backlog;
                sk->sk_state           = TCP_LISTEN;
                rc = 0;
        }
+       unlock_kernel();
 
        return rc;
 }
@@ -501,19 +508,25 @@ out:
        return sk;
 }
 
-static int x25_create(struct net *net, struct socket *sock, int protocol)
+static int x25_create(struct net *net, struct socket *sock, int protocol,
+                     int kern)
 {
        struct sock *sk;
        struct x25_sock *x25;
-       int rc = -ESOCKTNOSUPPORT;
+       int rc = -EAFNOSUPPORT;
 
-       if (net != &init_net)
-               return -EAFNOSUPPORT;
+       if (!net_eq(net, &init_net))
+               goto out;
+
+       rc = -ESOCKTNOSUPPORT;
+       if (sock->type != SOCK_SEQPACKET)
+               goto out;
 
-       if (sock->type != SOCK_SEQPACKET || protocol)
+       rc = -EINVAL;
+       if (protocol)
                goto out;
 
-       rc = -ENOMEM;
+       rc = -ENOBUFS;
        if ((sk = x25_alloc_socket(net)) == NULL)
                goto out;
 
@@ -597,6 +610,7 @@ static int x25_release(struct socket *sock)
        struct sock *sk = sock->sk;
        struct x25_sock *x25;
 
+       lock_kernel();
        if (!sk)
                goto out;
 
@@ -627,6 +641,7 @@ static int x25_release(struct socket *sock)
 
        sock_orphan(sk);
 out:
+       unlock_kernel();
        return 0;
 }
 
@@ -634,18 +649,31 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
        struct sock *sk = sock->sk;
        struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;
+       int len, i, rc = 0;
 
+       lock_kernel();
        if (!sock_flag(sk, SOCK_ZAPPED) ||
            addr_len != sizeof(struct sockaddr_x25) ||
-           addr->sx25_family != AF_X25)
-               return -EINVAL;
+           addr->sx25_family != AF_X25) {
+               rc = -EINVAL;
+               goto out;
+       }
+
+       len = strlen(addr->sx25_addr.x25_addr);
+       for (i = 0; i < len; i++) {
+               if (!isdigit(addr->sx25_addr.x25_addr[i])) {
+                       rc = -EINVAL;
+                       goto out;
+               }
+       }
 
        x25_sk(sk)->source_addr = addr->sx25_addr;
        x25_insert_socket(sk);
        sock_reset_flag(sk, SOCK_ZAPPED);
        SOCK_DEBUG(sk, "x25_bind: socket is bound\n");
-
-       return 0;
+out:
+       unlock_kernel();
+       return rc;
 }
 
 static int x25_wait_for_connection_establishment(struct sock *sk)
@@ -686,6 +714,7 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr,
        struct x25_route *rt;
        int rc = 0;
 
+       lock_kernel();
        lock_sock(sk);
        if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
                sock->state = SS_CONNECTED;
@@ -763,6 +792,7 @@ out_put_route:
        x25_route_put(rt);
 out:
        release_sock(sk);
+       unlock_kernel();
        return rc;
 }
 
@@ -802,6 +832,7 @@ static int x25_accept(struct socket *sock, struct socket *newsock, int flags)
        struct sk_buff *skb;
        int rc = -EINVAL;
 
+       lock_kernel();
        if (!sk || sk->sk_state != TCP_LISTEN)
                goto out;
 
@@ -829,6 +860,7 @@ static int x25_accept(struct socket *sock, struct socket *newsock, int flags)
 out2:
        release_sock(sk);
 out:
+       unlock_kernel();
        return rc;
 }
 
@@ -838,10 +870,14 @@ static int x25_getname(struct socket *sock, struct sockaddr *uaddr,
        struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)uaddr;
        struct sock *sk = sock->sk;
        struct x25_sock *x25 = x25_sk(sk);
+       int rc = 0;
 
+       lock_kernel();
        if (peer) {
-               if (sk->sk_state != TCP_ESTABLISHED)
-                       return -ENOTCONN;
+               if (sk->sk_state != TCP_ESTABLISHED) {
+                       rc = -ENOTCONN;
+                       goto out;
+               }
                sx25->sx25_addr = x25->dest_addr;
        } else
                sx25->sx25_addr = x25->source_addr;
@@ -849,7 +885,21 @@ static int x25_getname(struct socket *sock, struct sockaddr *uaddr,
        sx25->sx25_family = AF_X25;
        *uaddr_len = sizeof(*sx25);
 
-       return 0;
+out:
+       unlock_kernel();
+       return rc;
+}
+
+static unsigned int x25_datagram_poll(struct file *file, struct socket *sock,
+                          poll_table *wait)
+{
+       int rc;
+
+       lock_kernel();
+       rc = datagram_poll(file, sock, wait);
+       unlock_kernel();
+
+       return rc;
 }
 
 int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
@@ -1002,6 +1052,7 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
        size_t size;
        int qbit = 0, rc = -EINVAL;
 
+       lock_kernel();
        if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_OOB|MSG_EOR|MSG_CMSG_COMPAT))
                goto out;
 
@@ -1166,6 +1217,7 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
        release_sock(sk);
        rc = len;
 out:
+       unlock_kernel();
        return rc;
 out_kfree_skb:
        kfree_skb(skb);
@@ -1186,6 +1238,7 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
        unsigned char *asmptr;
        int rc = -ENOTCONN;
 
+       lock_kernel();
        /*
         * This works for seqpacket too. The receiver has ordered the queue for
         * us! We do one quick check first though
@@ -1259,6 +1312,7 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
 out_free_dgram:
        skb_free_datagram(sk, skb);
 out:
+       unlock_kernel();
        return rc;
 }
 
@@ -1270,6 +1324,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
        void __user *argp = (void __user *)arg;
        int rc;
 
+       lock_kernel();
        switch (cmd) {
                case TIOCOUTQ: {
                        int amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
@@ -1363,7 +1418,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                            facilities.throughput > 0xDD)
                                break;
                        if (facilities.reverse &&
-                               (facilities.reverse | 0x81)!= 0x81)
+                               (facilities.reverse & 0x81) != 0x81)
                                break;
                        x25->facilities = facilities;
                        rc = 0;
@@ -1430,6 +1485,17 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                        break;
                }
 
+               case SIOCX25SCAUSEDIAG: {
+                       struct x25_causediag causediag;
+                       rc = -EFAULT;
+                       if (copy_from_user(&causediag, argp, sizeof(causediag)))
+                               break;
+                       x25->causediag = causediag;
+                       rc = 0;
+                       break;
+
+               }
+
                case SIOCX25SCUDMATCHLEN: {
                        struct x25_subaddr sub_addr;
                        rc = -EINVAL;
@@ -1472,6 +1538,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                        rc = -ENOIOCTLCMD;
                        break;
        }
+       unlock_kernel();
 
        return rc;
 }
@@ -1542,15 +1609,19 @@ static int compat_x25_ioctl(struct socket *sock, unsigned int cmd,
                break;
        case SIOCGSTAMP:
                rc = -EINVAL;
+               lock_kernel();
                if (sk)
                        rc = compat_sock_get_timestamp(sk,
                                        (struct timeval __user*)argp);
+               unlock_kernel();
                break;
        case SIOCGSTAMPNS:
                rc = -EINVAL;
+               lock_kernel();
                if (sk)
                        rc = compat_sock_get_timestampns(sk,
                                        (struct timespec __user*)argp);
+               unlock_kernel();
                break;
        case SIOCGIFADDR:
        case SIOCSIFADDR:
@@ -1569,16 +1640,22 @@ static int compat_x25_ioctl(struct socket *sock, unsigned int cmd,
                rc = -EPERM;
                if (!capable(CAP_NET_ADMIN))
                        break;
+               lock_kernel();
                rc = x25_route_ioctl(cmd, argp);
+               unlock_kernel();
                break;
        case SIOCX25GSUBSCRIP:
+               lock_kernel();
                rc = compat_x25_subscr_ioctl(cmd, argp);
+               unlock_kernel();
                break;
        case SIOCX25SSUBSCRIP:
                rc = -EPERM;
                if (!capable(CAP_NET_ADMIN))
                        break;
+               lock_kernel();
                rc = compat_x25_subscr_ioctl(cmd, argp);
+               unlock_kernel();
                break;
        case SIOCX25GFACILITIES:
        case SIOCX25SFACILITIES:
@@ -1587,6 +1664,7 @@ static int compat_x25_ioctl(struct socket *sock, unsigned int cmd,
        case SIOCX25GCALLUSERDATA:
        case SIOCX25SCALLUSERDATA:
        case SIOCX25GCAUSEDIAG:
+       case SIOCX25SCAUSEDIAG:
        case SIOCX25SCUDMATCHLEN:
        case SIOCX25CALLACCPTAPPRV:
        case SIOCX25SENDCALLACCPT:
@@ -1600,7 +1678,7 @@ static int compat_x25_ioctl(struct socket *sock, unsigned int cmd,
 }
 #endif
 
-static const struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = {
+static const struct proto_ops x25_proto_ops = {
        .family =       AF_X25,
        .owner =        THIS_MODULE,
        .release =      x25_release,
@@ -1609,7 +1687,7 @@ static const struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = {
        .socketpair =   sock_no_socketpair,
        .accept =       x25_accept,
        .getname =      x25_getname,
-       .poll =         datagram_poll,
+       .poll =         x25_datagram_poll,
        .ioctl =        x25_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = compat_x25_ioctl,
@@ -1624,8 +1702,6 @@ static const struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = {
        .sendpage =     sock_no_sendpage,
 };
 
-SOCKOPS_WRAP(x25_proto, AF_X25);
-
 static struct packet_type x25_packet_type __read_mostly = {
        .type = cpu_to_be16(ETH_P_X25),
        .func = x25_lapb_receive_frame,
@@ -1659,20 +1735,31 @@ static int __init x25_init(void)
        if (rc != 0)
                goto out;
 
-       sock_register(&x25_family_ops);
+       rc = sock_register(&x25_family_ops);
+       if (rc != 0)
+               goto out_proto;
 
        dev_add_pack(&x25_packet_type);
 
-       register_netdevice_notifier(&x25_dev_notifier);
+       rc = register_netdevice_notifier(&x25_dev_notifier);
+       if (rc != 0)
+               goto out_sock;
 
        printk(KERN_INFO "X.25 for Linux Version 0.2\n");
 
-#ifdef CONFIG_SYSCTL
        x25_register_sysctl();
-#endif
-       x25_proc_init();
+       rc = x25_proc_init();
+       if (rc != 0)
+               goto out_dev;
 out:
        return rc;
+out_dev:
+       unregister_netdevice_notifier(&x25_dev_notifier);
+out_sock:
+       sock_unregister(AF_X25);
+out_proto:
+       proto_unregister(&x25_proto);
+       goto out;
 }
 module_init(x25_init);
 
@@ -1682,9 +1769,7 @@ static void __exit x25_exit(void)
        x25_link_free();
        x25_route_free();
 
-#ifdef CONFIG_SYSCTL
        x25_unregister_sysctl();
-#endif
 
        unregister_netdevice_notifier(&x25_dev_notifier);