vserver 1.9.5.x5
[linux-2.6.git] / net / x25 / af_x25.c
index 614f959..77fdf20 100644 (file)
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/string.h>
-#include <linux/sockios.h>
 #include <linux/net.h>
-#include <linux/stat.h>
-#include <linux/inet.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <net/tcp.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/fcntl.h>
 #include <linux/termios.h>     /* For TIOCINQ/OUTQ */
-#include <linux/mm.h>
-#include <linux/interrupt.h>
 #include <linux/notifier.h>
 #include <linux/init.h>
 #include <net/x25.h>
@@ -67,7 +58,7 @@ int sysctl_x25_clear_request_timeout   = X25_DEFAULT_T23;
 int sysctl_x25_ack_holdback_timeout    = X25_DEFAULT_T2;
 
 HLIST_HEAD(x25_list);
-rwlock_t x25_list_lock = RW_LOCK_UNLOCKED;
+DEFINE_RWLOCK(x25_list_lock);
 
 static struct proto_ops x25_proto_ops;
 
@@ -223,14 +214,19 @@ static void x25_insert_socket(struct sock *sk)
 
 /*
  *     Find a socket that wants to accept the Call Request we just
- *     received.
+ *     received. Check the full list for an address/cud match.
+ *     If no cuds match return the next_best thing, an address match.
+ *     Note: if a listening socket has cud set it must only get calls
+ *     with matching cud.
  */
-static struct sock *x25_find_listener(struct x25_address *addr)
+static struct sock *x25_find_listener(struct x25_address *addr, struct x25_calluserdata *calluserdata)
 {
        struct sock *s;
+       struct sock *next_best;
        struct hlist_node *node;
 
        read_lock_bh(&x25_list_lock);
+       next_best = NULL;
 
        sk_for_each(s, node, &x25_list)
                if ((!strcmp(addr->x25_addr,
@@ -238,9 +234,24 @@ static struct sock *x25_find_listener(struct x25_address *addr)
                     !strcmp(addr->x25_addr,
                             null_x25_address.x25_addr)) &&
                     s->sk_state == TCP_LISTEN) {
-                       sock_hold(s);
-                       goto found;
+
+                       /*
+                        * Found a listening socket, now check the incoming
+                        * call user data vs this sockets call user data
+                        */
+                       if (x25_check_calluserdata(&x25_sk(s)->calluserdata, calluserdata)) {
+                               sock_hold(s);
+                               goto found;
+                       }
+                       if (x25_sk(s)->calluserdata.cudlength == 0) {
+                               next_best = s;
+                       }
                }
+       if (next_best) {
+               s = next_best;
+               sock_hold(s);
+               goto found;
+       }
        s = NULL;
 found:
        read_unlock_bh(&x25_list_lock);
@@ -250,7 +261,7 @@ found:
 /*
  *     Find a connected X.25 socket given my LCI and neighbour.
  */
-struct sock *__x25_find_socket(unsigned int lci, struct x25_neigh *nb)
+static struct sock *__x25_find_socket(unsigned int lci, struct x25_neigh *nb)
 {
        struct sock *s;
        struct hlist_node *node;
@@ -278,7 +289,7 @@ struct sock *x25_find_socket(unsigned int lci, struct x25_neigh *nb)
 /*
  *     Find a unique LCI for a given device.
  */
-unsigned int x25_new_lci(struct x25_neigh *nb)
+static unsigned int x25_new_lci(struct x25_neigh *nb)
 {
        unsigned int lci = 1;
        struct sock *sk;
@@ -347,6 +358,7 @@ void x25_destroy_socket(struct sock *sk)
                /* Defer: outstanding buffers */
                sk->sk_timer.expires  = jiffies + 10 * HZ;
                sk->sk_timer.function = x25_destroy_timer;
+               sk->sk_timer.data = (unsigned long)sk;
                add_timer(&sk->sk_timer);
        } else {
                /* drop last reference so sock_put will free */
@@ -363,7 +375,7 @@ void x25_destroy_socket(struct sock *sk)
  */
 
 static int x25_setsockopt(struct socket *sock, int level, int optname,
-                         char *optval, int optlen)
+                         char __user *optval, int optlen)
 {
        int opt;
        struct sock *sk = sock->sk;
@@ -377,7 +389,7 @@ static int x25_setsockopt(struct socket *sock, int level, int optname,
                goto out;
 
        rc = -EFAULT;
-       if (get_user(opt, (int *)optval))
+       if (get_user(opt, (int __user *)optval))
                goto out;
 
        x25_sk(sk)->qbitincl = !!opt;
@@ -387,7 +399,7 @@ out:
 }
 
 static int x25_getsockopt(struct socket *sock, int level, int optname,
-                         char *optval, int *optlen)
+                         char __user *optval, int __user *optlen)
 {
        struct sock *sk = sock->sk;
        int val, len, rc = -ENOPROTOOPT;
@@ -478,8 +490,10 @@ static int x25_create(struct socket *sock, int protocol)
 
        x25 = x25_sk(sk);
 
-       sock_init_data(sock, sk);
-       sk_set_owner(sk, THIS_MODULE);
+       sk->sk_socket = sock;
+       sk->sk_type = sock->type;
+       sk->sk_sleep = &sock->wait;
+       sock->sk = sk;
 
        x25_init_timers(sk);
 
@@ -769,7 +783,6 @@ static int x25_accept(struct socket *sock, struct socket *newsock, int flags)
        if (!skb->sk)
                goto out2;
        newsk            = skb->sk;
-       newsk->sk_pair   = NULL;
        newsk->sk_socket = newsock;
        newsk->sk_sleep  = &newsock->wait;
 
@@ -814,6 +827,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
        struct x25_opt *makex25;
        struct x25_address source_addr, dest_addr;
        struct x25_facilities facilities;
+       struct x25_calluserdata calluserdata;
        int len, rc;
 
        /*
@@ -828,9 +842,27 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
        skb_pull(skb, x25_addr_ntoa(skb->data, &source_addr, &dest_addr));
 
        /*
-        *      Find a listener for the particular address.
+        *      Get the length of the facilities, skip past them for the moment
+        *      get the call user data because this is needed to determine
+        *      the correct listener
         */
-       sk = x25_find_listener(&source_addr);
+       len = skb->data[0] + 1;
+       skb_pull(skb,len);
+
+       /*
+        *      Incoming Call User Data.
+        */
+       if (skb->len >= 0) {
+               memcpy(calluserdata.cuddata, skb->data, skb->len);
+               calluserdata.cudlength = skb->len;
+       }
+
+       skb_push(skb,len);
+
+       /*
+        *      Find a listener for the particular address/cud pair.
+        */
+       sk = x25_find_listener(&source_addr,&calluserdata);
 
        /*
         *      We can't accept the Call Request.
@@ -859,7 +891,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
                goto out_sock_put;
 
        /*
-        *      Remove the facilities, leaving any Call User Data.
+        *      Remove the facilities
         */
        skb_pull(skb, len);
 
@@ -873,21 +905,13 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
        makex25->neighbour     = nb;
        makex25->facilities    = facilities;
        makex25->vc_facil_mask = x25_sk(sk)->vc_facil_mask;
+       makex25->calluserdata  = calluserdata;
 
        x25_write_internal(make, X25_CALL_ACCEPTED);
 
-       /*
-        *      Incoming Call User Data.
-        */
-       if (skb->len >= 0) {
-               memcpy(makex25->calluserdata.cuddata, skb->data, skb->len);
-               makex25->calluserdata.cudlength = skb->len;
-       }
-
        makex25->state = X25_STATE_3;
 
        sk->sk_ack_backlog++;
-       make->sk_pair = sk;
 
        x25_insert_socket(make);
 
@@ -922,7 +946,7 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
        size_t size;
        int qbit = 0, rc = -EINVAL;
 
-       if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_OOB | MSG_EOR))
+       if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_OOB|MSG_EOR|MSG_CMSG_COMPAT))
                goto out;
 
        /* we currently don't support segmented records at the user interface */
@@ -1180,6 +1204,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
        struct sock *sk = sock->sk;
        struct x25_opt *x25 = x25_sk(sk);
+       void __user *argp = (void __user *)arg;
        int rc;
 
        switch (cmd) {
@@ -1188,7 +1213,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                                     atomic_read(&sk->sk_wmem_alloc);
                        if (amount < 0)
                                amount = 0;
-                       rc = put_user(amount, (unsigned int *)arg);
+                       rc = put_user(amount, (unsigned int __user *)argp);
                        break;
                }
 
@@ -1201,7 +1226,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                         */
                        if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL)
                                amount = skb->len;
-                       rc = put_user(amount, (unsigned int *)arg);
+                       rc = put_user(amount, (unsigned int __user *)argp);
                        break;
                }
 
@@ -1209,7 +1234,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                        rc = -EINVAL;
                        if (sk)
                                rc = sock_get_timestamp(sk, 
-                                               (struct timeval *)arg); 
+                                               (struct timeval __user *)argp); 
                        break;
                case SIOCGIFADDR:
                case SIOCSIFADDR:
@@ -1228,20 +1253,20 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                        rc = -EPERM;
                        if (!capable(CAP_NET_ADMIN))
                                break;
-                       rc = x25_route_ioctl(cmd, (void *)arg);
+                       rc = x25_route_ioctl(cmd, argp);
                        break;
                case SIOCX25GSUBSCRIP:
-                       rc = x25_subscr_ioctl(cmd, (void *)arg);
+                       rc = x25_subscr_ioctl(cmd, argp);
                        break;
                case SIOCX25SSUBSCRIP:
                        rc = -EPERM;
                        if (!capable(CAP_NET_ADMIN))
                                break;
-                       rc = x25_subscr_ioctl(cmd, (void *)arg);
+                       rc = x25_subscr_ioctl(cmd, argp);
                        break;
                case SIOCX25GFACILITIES: {
                        struct x25_facilities fac = x25->facilities;
-                       rc = copy_to_user((void *)arg, &fac,
+                       rc = copy_to_user(argp, &fac,
                                          sizeof(fac)) ? -EFAULT : 0;
                        break;
                }
@@ -1249,7 +1274,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                case SIOCX25SFACILITIES: {
                        struct x25_facilities facilities;
                        rc = -EFAULT;
-                       if (copy_from_user(&facilities, (void *)arg,
+                       if (copy_from_user(&facilities, argp,
                                           sizeof(facilities)))
                                break;
                        rc = -EINVAL;
@@ -1277,7 +1302,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 
                case SIOCX25GCALLUSERDATA: {
                        struct x25_calluserdata cud = x25->calluserdata;
-                       rc = copy_to_user((void *)arg, &cud,
+                       rc = copy_to_user(argp, &cud,
                                          sizeof(cud)) ? -EFAULT : 0;
                        break;
                }
@@ -1286,7 +1311,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                        struct x25_calluserdata calluserdata;
 
                        rc = -EFAULT;
-                       if (copy_from_user(&calluserdata, (void *)arg,
+                       if (copy_from_user(&calluserdata, argp,
                                           sizeof(calluserdata)))
                                break;
                        rc = -EINVAL;
@@ -1300,20 +1325,20 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                case SIOCX25GCAUSEDIAG: {
                        struct x25_causediag causediag;
                        causediag = x25->causediag;
-                       rc = copy_to_user((void *)arg, &causediag,
+                       rc = copy_to_user(argp, &causediag,
                                          sizeof(causediag)) ? -EFAULT : 0;
                        break;
                }
 
                default:
-                       rc = dev_ioctl(cmd, (void *)arg);
+                       rc = dev_ioctl(cmd, argp);
                        break;
        }
 
        return rc;
 }
 
-struct net_proto_family x25_family_ops = {
+static struct net_proto_family x25_family_ops = {
        .family =       AF_X25,
        .create =       x25_create,
        .owner  =       THIS_MODULE,
@@ -1348,7 +1373,7 @@ static struct packet_type x25_packet_type = {
        .func = x25_lapb_receive_frame,
 };
 
-struct notifier_block x25_dev_notifier = {
+static struct notifier_block x25_dev_notifier = {
        .notifier_call = x25_device_event,
 };