* 2000-11-14 Henner Eisen Closing datalink from NETDEV_GOING_DOWN
* 2002-10-06 Arnaldo C. Melo Get rid of cli/sti, move proc stuff to
* x25_proc.c, using seq_file
+ * 2005-04-02 Shaun Pereira Selective sub address matching
+ * with call user data
+ * 2005-04-15 Shaun Pereira Fast select with no restriction on
+ * response
*/
-#include <linux/config.h>
#include <linux/module.h>
+#include <linux/capability.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 <net/tcp_states.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 <linux/compat.h>
+
#include <net/x25.h>
+#include <net/compat.h>
int sysctl_x25_restart_request_timeout = X25_DEFAULT_T20;
int sysctl_x25_call_request_timeout = X25_DEFAULT_T21;
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;
+static const struct proto_ops x25_proto_ops;
static struct x25_address null_x25_address = {" "};
+#ifdef CONFIG_COMPAT
+struct compat_x25_subscrip_struct {
+ char device[200-sizeof(compat_ulong_t)];
+ compat_ulong_t global_facil_mask;
+ compat_uint_t extended;
+};
+#endif
+
int x25_addr_ntoa(unsigned char *p, struct x25_address *called_addr,
struct x25_address *calling_addr)
{
/*
* 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 sk_buff *skb)
{
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,
- x25_sk(s)->source_addr.x25_addr) ||
- !strcmp(addr->x25_addr,
- null_x25_address.x25_addr)) &&
- s->sk_state == TCP_LISTEN) {
- sock_hold(s);
- goto found;
+ x25_sk(s)->source_addr.x25_addr) ||
+ !strcmp(addr->x25_addr,
+ null_x25_address.x25_addr)) &&
+ s->sk_state == TCP_LISTEN) {
+ /*
+ * Found a listening socket, now check the incoming
+ * call user data vs this sockets call user data
+ */
+ if(skb->len > 0 && x25_sk(s)->cudmatchlength > 0) {
+ if((memcmp(x25_sk(s)->calluserdata.cuddata,
+ skb->data,
+ x25_sk(s)->cudmatchlength)) == 0) {
+ sock_hold(s);
+ goto found;
+ }
+ } else
+ 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;
return rc;
}
+static struct proto x25_proto = {
+ .name = "X25",
+ .owner = THIS_MODULE,
+ .obj_size = sizeof(struct x25_sock),
+};
+
static struct sock *x25_alloc_socket(void)
{
- struct x25_opt *x25;
- struct sock *sk = sk_alloc(AF_X25, GFP_ATOMIC, 1, NULL);
+ struct x25_sock *x25;
+ struct sock *sk = sk_alloc(AF_X25, GFP_ATOMIC, &x25_proto, 1);
if (!sk)
goto out;
- x25 = sk->sk_protinfo = kmalloc(sizeof(*x25), GFP_ATOMIC);
- if (!x25)
- goto frees;
-
- memset(x25, 0, sizeof(*x25));
-
- x25->sk = sk;
-
sock_init_data(NULL, sk);
- sk_set_owner(sk, THIS_MODULE);
+ x25 = x25_sk(sk);
skb_queue_head_init(&x25->ack_queue);
skb_queue_head_init(&x25->fragment_queue);
skb_queue_head_init(&x25->interrupt_in_queue);
skb_queue_head_init(&x25->interrupt_out_queue);
out:
return sk;
-frees:
- sk_free(sk);
- sk = NULL;
- goto out;
}
-void x25_init_timers(struct sock *sk);
-
static int x25_create(struct socket *sock, int protocol)
{
struct sock *sk;
- struct x25_opt *x25;
+ struct x25_sock *x25;
int rc = -ESOCKTNOSUPPORT;
if (sock->type != SOCK_SEQPACKET || 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);
x25->t23 = sysctl_x25_clear_request_timeout;
x25->t2 = sysctl_x25_ack_holdback_timeout;
x25->state = X25_STATE_0;
+ x25->cudmatchlength = 0;
+ x25->accptapprv = X25_DENY_ACCPT_APPRV; /* normally no cud */
+ /* on call accept */
x25->facilities.winsize_in = X25_DEFAULT_WINDOW_SIZE;
x25->facilities.winsize_out = X25_DEFAULT_WINDOW_SIZE;
x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE;
x25->facilities.throughput = X25_DEFAULT_THROUGHPUT;
x25->facilities.reverse = X25_DEFAULT_REVERSE;
+ x25->dte_facilities.calling_len = 0;
+ x25->dte_facilities.called_len = 0;
+ memset(x25->dte_facilities.called_ae, '\0',
+ sizeof(x25->dte_facilities.called_ae));
+ memset(x25->dte_facilities.calling_ae, '\0',
+ sizeof(x25->dte_facilities.calling_ae));
+
rc = 0;
out:
return rc;
static struct sock *x25_make_new(struct sock *osk)
{
struct sock *sk = NULL;
- struct x25_opt *x25, *ox25;
+ struct x25_sock *x25, *ox25;
if (osk->sk_type != SOCK_SEQPACKET)
goto out;
sk->sk_protocol = osk->sk_protocol;
sk->sk_rcvbuf = osk->sk_rcvbuf;
sk->sk_sndbuf = osk->sk_sndbuf;
- sk->sk_debug = osk->sk_debug;
sk->sk_state = TCP_ESTABLISHED;
sk->sk_sleep = osk->sk_sleep;
- sk->sk_zapped = osk->sk_zapped;
sk->sk_backlog_rcv = osk->sk_backlog_rcv;
+ sock_copy_flags(sk, osk);
ox25 = x25_sk(osk);
x25->t21 = ox25->t21;
x25->t2 = ox25->t2;
x25->facilities = ox25->facilities;
x25->qbitincl = ox25->qbitincl;
+ x25->dte_facilities = ox25->dte_facilities;
+ x25->cudmatchlength = ox25->cudmatchlength;
+ x25->accptapprv = ox25->accptapprv;
x25_init_timers(sk);
out:
static int x25_release(struct socket *sock)
{
struct sock *sk = sock->sk;
- struct x25_opt *x25;
+ struct x25_sock *x25;
if (!sk)
goto out;
struct sock *sk = sock->sk;
struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;
- if (!sk->sk_zapped ||
+ if (!sock_flag(sk, SOCK_ZAPPED) ||
addr_len != sizeof(struct sockaddr_x25) ||
addr->sx25_family != AF_X25)
return -EINVAL;
x25_sk(sk)->source_addr = addr->sx25_addr;
x25_insert_socket(sk);
- sk->sk_zapped = 0;
+ sock_reset_flag(sk, SOCK_ZAPPED);
SOCK_DEBUG(sk, "x25_bind: socket is bound\n");
return 0;
int addr_len, int flags)
{
struct sock *sk = sock->sk;
- struct x25_opt *x25 = x25_sk(sk);
+ struct x25_sock *x25 = x25_sk(sk);
struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;
struct x25_route *rt;
int rc = 0;
goto out_put_neigh;
rc = -EINVAL;
- if (sk->sk_zapped) /* Must bind first - autobinding does not work */
+ if (sock_flag(sk, SOCK_ZAPPED)) /* Must bind first - autobinding does not work */
goto out_put_neigh;
if (!strcmp(x25->source_addr.x25_addr, null_x25_address.x25_addr))
return rc;
}
-static int x25_wait_for_data(struct sock *sk, int timeout)
+static int x25_wait_for_data(struct sock *sk, long timeout)
{
DECLARE_WAITQUEUE(wait, current);
int rc = 0;
if (!skb->sk)
goto out2;
newsk = skb->sk;
- newsk->sk_pair = NULL;
newsk->sk_socket = newsock;
newsk->sk_sleep = &newsock->wait;
{
struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)uaddr;
struct sock *sk = sock->sk;
- struct x25_opt *x25 = x25_sk(sk);
+ struct x25_sock *x25 = x25_sk(sk);
if (peer) {
if (sk->sk_state != TCP_ESTABLISHED)
{
struct sock *sk;
struct sock *make;
- struct x25_opt *makex25;
+ struct x25_sock *makex25;
struct x25_address source_addr, dest_addr;
struct x25_facilities facilities;
+ struct x25_dte_facilities dte_facilities;
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
+ */
+ len = skb->data[0] + 1;
+ skb_pull(skb,len);
+
+ /*
+ * Find a listener for the particular address/cud pair.
*/
- sk = x25_find_listener(&source_addr);
+ sk = x25_find_listener(&source_addr,skb);
+ skb_push(skb,len);
/*
* We can't accept the Call Request.
*/
- if (!sk || sk->sk_ack_backlog == sk->sk_max_ack_backlog)
+ if (sk == NULL || sk_acceptq_is_full(sk))
goto out_clear_request;
/*
* Try to reach a compromise on the requested facilities.
*/
- if ((len = x25_negotiate_facilities(skb, sk, &facilities)) == -1)
+ len = x25_negotiate_facilities(skb, sk, &facilities, &dte_facilities);
+ if (len == -1)
goto out_sock_put;
/*
goto out_sock_put;
/*
- * Remove the facilities, leaving any Call User Data.
+ * Remove the facilities
*/
skb_pull(skb, len);
makex25->source_addr = source_addr;
makex25->neighbour = nb;
makex25->facilities = facilities;
+ makex25->dte_facilities= dte_facilities;
makex25->vc_facil_mask = x25_sk(sk)->vc_facil_mask;
-
- x25_write_internal(make, X25_CALL_ACCEPTED);
+ /* ensure no reverse facil on accept */
+ makex25->vc_facil_mask &= ~X25_MASK_REVERSE;
+ /* ensure no calling address extension on accept */
+ makex25->vc_facil_mask &= ~X25_MASK_CALLING_AE;
+ makex25->cudmatchlength = x25_sk(sk)->cudmatchlength;
+
+ /* Normally all calls are accepted immediatly */
+ if(makex25->accptapprv & X25_DENY_ACCPT_APPRV) {
+ x25_write_internal(make, X25_CALL_ACCEPTED);
+ makex25->state = X25_STATE_3;
+ }
/*
* Incoming Call User Data.
makex25->calluserdata.cudlength = skb->len;
}
- makex25->state = X25_STATE_3;
-
sk->sk_ack_backlog++;
- make->sk_pair = sk;
x25_insert_socket(make);
struct msghdr *msg, size_t len)
{
struct sock *sk = sock->sk;
- struct x25_opt *x25 = x25_sk(sk);
+ struct x25_sock *x25 = x25_sk(sk);
struct sockaddr_x25 *usx25 = (struct sockaddr_x25 *)msg->msg_name;
struct sockaddr_x25 sx25;
struct sk_buff *skb;
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 */
goto out;
rc = -EADDRNOTAVAIL;
- if (sk->sk_zapped)
+ if (sock_flag(sk, SOCK_ZAPPED))
goto out;
rc = -EPIPE;
int flags)
{
struct sock *sk = sock->sk;
- struct x25_opt *x25 = x25_sk(sk);
+ struct x25_sock *x25 = x25_sk(sk);
struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name;
size_t copied;
int qbit;
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);
+ struct x25_sock *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;
if (facilities.throughput < 0x03 ||
facilities.throughput > 0xDD)
break;
- if (facilities.reverse && facilities.reverse != 1)
+ if (facilities.reverse &&
+ (facilities.reverse | 0x81)!= 0x81)
break;
x25->facilities = facilities;
rc = 0;
break;
}
+ case SIOCX25GDTEFACILITIES: {
+ rc = copy_to_user(argp, &x25->dte_facilities,
+ sizeof(x25->dte_facilities));
+ if (rc)
+ rc = -EFAULT;
+ break;
+ }
+
+ case SIOCX25SDTEFACILITIES: {
+ struct x25_dte_facilities dtefacs;
+ rc = -EFAULT;
+ if (copy_from_user(&dtefacs, argp, sizeof(dtefacs)))
+ break;
+ rc = -EINVAL;
+ if (sk->sk_state != TCP_LISTEN &&
+ sk->sk_state != TCP_CLOSE)
+ break;
+ if (dtefacs.calling_len > X25_MAX_AE_LEN)
+ break;
+ if (dtefacs.calling_ae == NULL)
+ break;
+ if (dtefacs.called_len > X25_MAX_AE_LEN)
+ break;
+ if (dtefacs.called_ae == NULL)
+ break;
+ x25->dte_facilities = dtefacs;
+ rc = 0;
+ break;
+ }
+
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;
}
+ case SIOCX25SCUDMATCHLEN: {
+ struct x25_subaddr sub_addr;
+ rc = -EINVAL;
+ if(sk->sk_state != TCP_CLOSE)
+ break;
+ rc = -EFAULT;
+ if (copy_from_user(&sub_addr, argp,
+ sizeof(sub_addr)))
+ break;
+ rc = -EINVAL;
+ if(sub_addr.cudmatchlength > X25_MAX_CUD_LEN)
+ break;
+ x25->cudmatchlength = sub_addr.cudmatchlength;
+ rc = 0;
+ break;
+ }
+
+ case SIOCX25CALLACCPTAPPRV: {
+ rc = -EINVAL;
+ if (sk->sk_state != TCP_CLOSE)
+ break;
+ x25->accptapprv = X25_ALLOW_ACCPT_APPRV;
+ rc = 0;
+ break;
+ }
+
+ case SIOCX25SENDCALLACCPT: {
+ rc = -EINVAL;
+ if (sk->sk_state != TCP_ESTABLISHED)
+ break;
+ if (x25->accptapprv) /* must call accptapprv above */
+ break;
+ x25_write_internal(sk, X25_CALL_ACCEPTED);
+ x25->state = X25_STATE_3;
+ rc = 0;
+ break;
+ }
+
default:
- rc = dev_ioctl(cmd, (void *)arg);
+ rc = -ENOIOCTLCMD;
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,
};
-static struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = {
+#ifdef CONFIG_COMPAT
+static int compat_x25_subscr_ioctl(unsigned int cmd,
+ struct compat_x25_subscrip_struct __user *x25_subscr32)
+{
+ struct compat_x25_subscrip_struct x25_subscr;
+ struct x25_neigh *nb;
+ struct net_device *dev;
+ int rc = -EINVAL;
+
+ rc = -EFAULT;
+ if (copy_from_user(&x25_subscr, x25_subscr32, sizeof(*x25_subscr32)))
+ goto out;
+
+ rc = -EINVAL;
+ dev = x25_dev_get(x25_subscr.device);
+ if (dev == NULL)
+ goto out;
+
+ nb = x25_get_neigh(dev);
+ if (nb == NULL)
+ goto out_dev_put;
+
+ dev_put(dev);
+
+ if (cmd == SIOCX25GSUBSCRIP) {
+ x25_subscr.extended = nb->extended;
+ x25_subscr.global_facil_mask = nb->global_facil_mask;
+ rc = copy_to_user(x25_subscr32, &x25_subscr,
+ sizeof(*x25_subscr32)) ? -EFAULT : 0;
+ } else {
+ rc = -EINVAL;
+ if (x25_subscr.extended == 0 || x25_subscr.extended == 1) {
+ rc = 0;
+ nb->extended = x25_subscr.extended;
+ nb->global_facil_mask = x25_subscr.global_facil_mask;
+ }
+ }
+ x25_neigh_put(nb);
+out:
+ return rc;
+out_dev_put:
+ dev_put(dev);
+ goto out;
+}
+
+static int compat_x25_ioctl(struct socket *sock, unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *argp = compat_ptr(arg);
+ struct sock *sk = sock->sk;
+
+ int rc = -ENOIOCTLCMD;
+
+ switch(cmd) {
+ case TIOCOUTQ:
+ case TIOCINQ:
+ rc = x25_ioctl(sock, cmd, (unsigned long)argp);
+ break;
+ case SIOCGSTAMP:
+ rc = -EINVAL;
+ if (sk)
+ rc = compat_sock_get_timestamp(sk,
+ (struct timeval __user*)argp);
+ break;
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ case SIOCGIFDSTADDR:
+ case SIOCSIFDSTADDR:
+ case SIOCGIFBRDADDR:
+ case SIOCSIFBRDADDR:
+ case SIOCGIFNETMASK:
+ case SIOCSIFNETMASK:
+ case SIOCGIFMETRIC:
+ case SIOCSIFMETRIC:
+ rc = -EINVAL;
+ break;
+ case SIOCADDRT:
+ case SIOCDELRT:
+ rc = -EPERM;
+ if (!capable(CAP_NET_ADMIN))
+ break;
+ rc = x25_route_ioctl(cmd, argp);
+ break;
+ case SIOCX25GSUBSCRIP:
+ rc = compat_x25_subscr_ioctl(cmd, argp);
+ break;
+ case SIOCX25SSUBSCRIP:
+ rc = -EPERM;
+ if (!capable(CAP_NET_ADMIN))
+ break;
+ rc = compat_x25_subscr_ioctl(cmd, argp);
+ break;
+ case SIOCX25GFACILITIES:
+ case SIOCX25SFACILITIES:
+ case SIOCX25GDTEFACILITIES:
+ case SIOCX25SDTEFACILITIES:
+ case SIOCX25GCALLUSERDATA:
+ case SIOCX25SCALLUSERDATA:
+ case SIOCX25GCAUSEDIAG:
+ case SIOCX25SCUDMATCHLEN:
+ case SIOCX25CALLACCPTAPPRV:
+ case SIOCX25SENDCALLACCPT:
+ rc = x25_ioctl(sock, cmd, (unsigned long)argp);
+ break;
+ default:
+ rc = -ENOIOCTLCMD;
+ break;
+ }
+ return rc;
+}
+#endif
+
+static const struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = {
.family = AF_X25,
.owner = THIS_MODULE,
.release = x25_release,
.getname = x25_getname,
.poll = datagram_poll,
.ioctl = x25_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = compat_x25_ioctl,
+#endif
.listen = x25_listen,
.shutdown = sock_no_shutdown,
.setsockopt = x25_setsockopt,
.func = x25_lapb_receive_frame,
};
-struct notifier_block x25_dev_notifier = {
+static struct notifier_block x25_dev_notifier = {
.notifier_call = x25_device_event,
};
static int __init x25_init(void)
{
+ int rc = proto_register(&x25_proto, 0);
+
+ if (rc != 0)
+ goto out;
+
sock_register(&x25_family_ops);
dev_add_pack(&x25_packet_type);
x25_register_sysctl();
#endif
x25_proc_init();
- return 0;
+out:
+ return rc;
}
module_init(x25_init);
dev_remove_pack(&x25_packet_type);
sock_unregister(AF_X25);
+ proto_unregister(&x25_proto);
}
module_exit(x25_exit);