#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>
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;
/*
* 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,
!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);
/*
* 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;
/*
* 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;
/* 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 */
*/
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;
goto out;
rc = -EFAULT;
- if (get_user(opt, (int *)optval))
+ if (get_user(opt, (int __user *)optval))
goto out;
x25_sk(sk)->qbitincl = !!opt;
}
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;
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);
if (!skb->sk)
goto out2;
newsk = skb->sk;
- newsk->sk_pair = NULL;
newsk->sk_socket = newsock;
newsk->sk_sleep = &newsock->wait;
struct x25_opt *makex25;
struct x25_address source_addr, dest_addr;
struct x25_facilities facilities;
+ struct x25_calluserdata calluserdata;
int len, rc;
/*
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.
goto out_sock_put;
/*
- * Remove the facilities, leaving any Call User Data.
+ * Remove the facilities
*/
skb_pull(skb, len);
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);
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 */
{
struct sock *sk = sock->sk;
struct x25_opt *x25 = x25_sk(sk);
+ void __user *argp = (void __user *)arg;
int rc;
switch (cmd) {
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;
}
*/
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;
}
rc = -EINVAL;
if (sk)
rc = sock_get_timestamp(sk,
- (struct timeval *)arg);
+ (struct timeval __user *)argp);
break;
case SIOCGIFADDR:
case SIOCSIFADDR:
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;
}
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;
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;
}
struct x25_calluserdata calluserdata;
rc = -EFAULT;
- if (copy_from_user(&calluserdata, (void *)arg,
+ if (copy_from_user(&calluserdata, argp,
sizeof(calluserdata)))
break;
rc = -EINVAL;
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,
.func = x25_lapb_receive_frame,
};
-struct notifier_block x25_dev_notifier = {
+static struct notifier_block x25_dev_notifier = {
.notifier_call = x25_device_event,
};