summaryrefslogtreecommitdiff
path: root/net/x25/af_x25.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/x25/af_x25.c')
-rw-r--r--net/x25/af_x25.c286
1 files changed, 145 insertions, 141 deletions
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index 45a3ab5612c1..af8762b24039 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* X.25 Packet Layer release 002
*
@@ -7,12 +8,6 @@
*
* This code REQUIRES 2.1.15 or higher
*
- * This module:
- * This module is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* History
* X.25 001 Jonathan Naylor Started coding.
* X.25 002 Jonathan Naylor Centralised disconnect handling.
@@ -35,11 +30,13 @@
* response
*/
+#define pr_fmt(fmt) "X25: " fmt
+
#include <linux/module.h>
#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
+#include <linux/sched/signal.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/net.h>
@@ -49,7 +46,7 @@
#include <linux/slab.h>
#include <net/sock.h>
#include <net/tcp_states.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/fcntl.h>
#include <linux/termios.h> /* For TIOCINQ/OUTQ */
#include <linux/notifier.h>
@@ -72,7 +69,7 @@ DEFINE_RWLOCK(x25_list_lock);
static const struct proto_ops x25_proto_ops;
-static struct x25_address null_x25_address = {" "};
+static const struct x25_address null_x25_address = {" "};
#ifdef CONFIG_COMPAT
struct compat_x25_subscrip_struct {
@@ -98,7 +95,7 @@ int x25_parse_address_block(struct sk_buff *skb,
}
len = *skb->data;
- needed = 1 + (len >> 4) + (len & 0x0f);
+ needed = 1 + ((len >> 4) + (len & 0x0f) + 1) / 2;
if (!pskb_may_pull(skb, needed)) {
/* packet is too short to hold the addresses it claims
@@ -203,22 +200,6 @@ static void x25_remove_socket(struct sock *sk)
}
/*
- * Kill all bound sockets on a dropped device.
- */
-static void x25_kill_by_device(struct net_device *dev)
-{
- struct sock *s;
-
- write_lock_bh(&x25_list_lock);
-
- sk_for_each(s, &x25_list)
- if (x25_sk(s)->neighbour && x25_sk(s)->neighbour->dev == dev)
- x25_disconnect(s, ENETUNREACH, 0, 0);
-
- write_unlock_bh(&x25_list_lock);
-}
-
-/*
* Handle device status changes.
*/
static int x25_device_event(struct notifier_block *this, unsigned long event,
@@ -230,27 +211,33 @@ static int x25_device_event(struct notifier_block *this, unsigned long event,
if (!net_eq(dev_net(dev), &init_net))
return NOTIFY_DONE;
- if (dev->type == ARPHRD_X25
-#if IS_ENABLED(CONFIG_LLC)
- || dev->type == ARPHRD_ETHER
-#endif
- ) {
+ if (dev->type == ARPHRD_X25) {
switch (event) {
- case NETDEV_UP:
+ case NETDEV_REGISTER:
+ case NETDEV_POST_TYPE_CHANGE:
x25_link_device_up(dev);
break;
- case NETDEV_GOING_DOWN:
+ case NETDEV_DOWN:
nb = x25_get_neigh(dev);
if (nb) {
- x25_terminate_link(nb);
+ x25_link_terminated(nb);
x25_neigh_put(nb);
}
- break;
- case NETDEV_DOWN:
- x25_kill_by_device(dev);
x25_route_device_down(dev);
+ break;
+ case NETDEV_PRE_TYPE_CHANGE:
+ case NETDEV_UNREGISTER:
x25_link_device_down(dev);
break;
+ case NETDEV_CHANGE:
+ if (!netif_carrier_ok(dev)) {
+ nb = x25_get_neigh(dev);
+ if (nb) {
+ x25_link_terminated(nb);
+ x25_neigh_put(nb);
+ }
+ }
+ break;
}
}
@@ -286,7 +273,7 @@ static struct sock *x25_find_listener(struct x25_address *addr,
sk_for_each(s, &x25_list)
if ((!strcmp(addr->x25_addr,
x25_sk(s)->source_addr.x25_addr) ||
- !strcmp(addr->x25_addr,
+ !strcmp(x25_sk(s)->source_addr.x25_addr,
null_x25_address.x25_addr)) &&
s->sk_state == TCP_LISTEN) {
/*
@@ -350,17 +337,15 @@ static unsigned int x25_new_lci(struct x25_neigh *nb)
unsigned int lci = 1;
struct sock *sk;
- read_lock_bh(&x25_list_lock);
-
- while ((sk = __x25_find_socket(lci, nb)) != NULL) {
+ while ((sk = x25_find_socket(lci, nb)) != NULL) {
sock_put(sk);
if (++lci == 4096) {
lci = 0;
break;
}
+ cond_resched();
}
- read_unlock_bh(&x25_list_lock);
return lci;
}
@@ -372,14 +357,16 @@ static void __x25_destroy_socket(struct sock *);
/*
* handler for deferred kills.
*/
-static void x25_destroy_timer(unsigned long data)
+static void x25_destroy_timer(struct timer_list *t)
{
- x25_destroy_socket_from_timer((struct sock *)data);
+ struct sock *sk = timer_container_of(sk, t, sk_timer);
+
+ x25_destroy_socket_from_timer(sk);
}
/*
* This is called from user mode and the timers. Thus it protects itself
- * against interrupt users but doesn't worry about being called during
+ * against interrupting users but doesn't worry about being called during
* work. Once it is removed from the queue no interrupt or bottom half
* will touch it and we are (fairly 8-) ) safe.
* Not static as it's used by the timer
@@ -412,7 +399,6 @@ static 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 */
@@ -435,7 +421,7 @@ void x25_destroy_socket_from_timer(struct sock *sk)
*/
static int x25_setsockopt(struct socket *sock, int level, int optname,
- char __user *optval, unsigned int optlen)
+ sockptr_t optval, unsigned int optlen)
{
int opt;
struct sock *sk = sock->sk;
@@ -449,7 +435,7 @@ static int x25_setsockopt(struct socket *sock, int level, int optname,
goto out;
rc = -EFAULT;
- if (get_user(opt, (int __user *)optval))
+ if (copy_from_sockptr(&opt, optval, sizeof(int)))
goto out;
if (opt)
@@ -474,12 +460,12 @@ static int x25_getsockopt(struct socket *sock, int level, int optname,
if (get_user(len, optlen))
goto out;
- len = min_t(unsigned int, len, sizeof(int));
-
rc = -EINVAL;
if (len < 0)
goto out;
+ len = min_t(unsigned int, len, sizeof(int));
+
rc = -EFAULT;
if (put_user(len, optlen))
goto out;
@@ -496,6 +482,12 @@ static int x25_listen(struct socket *sock, int backlog)
int rc = -EOPNOTSUPP;
lock_sock(sk);
+ if (sock->state != SS_UNCONNECTED) {
+ rc = -EINVAL;
+ release_sock(sk);
+ return rc;
+ }
+
if (sk->sk_state != TCP_LISTEN) {
memset(&x25_sk(sk)->dest_addr, 0, X25_ADDR_LEN);
sk->sk_max_ack_backlog = backlog;
@@ -513,10 +505,10 @@ static struct proto x25_proto = {
.obj_size = sizeof(struct x25_sock),
};
-static struct sock *x25_alloc_socket(struct net *net)
+static struct sock *x25_alloc_socket(struct net *net, int kern)
{
struct x25_sock *x25;
- struct sock *sk = sk_alloc(net, AF_X25, GFP_ATOMIC, &x25_proto);
+ struct sock *sk = sk_alloc(net, AF_X25, GFP_ATOMIC, &x25_proto, kern);
if (!sk)
goto out;
@@ -550,8 +542,8 @@ static int x25_create(struct net *net, struct socket *sock, int protocol,
if (protocol)
goto out;
- rc = -ENOBUFS;
- if ((sk = x25_alloc_socket(net)) == NULL)
+ rc = -ENOMEM;
+ if ((sk = x25_alloc_socket(net, kern)) == NULL)
goto out;
x25 = x25_sk(sk);
@@ -600,13 +592,13 @@ static struct sock *x25_make_new(struct sock *osk)
if (osk->sk_type != SOCK_SEQPACKET)
goto out;
- if ((sk = x25_alloc_socket(sock_net(osk))) == NULL)
+ if ((sk = x25_alloc_socket(sock_net(osk), 0)) == NULL)
goto out;
x25 = x25_sk(sk);
sk->sk_type = osk->sk_type;
- sk->sk_priority = osk->sk_priority;
+ sk->sk_priority = READ_ONCE(osk->sk_priority);
sk->sk_protocol = osk->sk_protocol;
sk->sk_rcvbuf = osk->sk_rcvbuf;
sk->sk_sndbuf = osk->sk_sndbuf;
@@ -663,6 +655,12 @@ static int x25_release(struct socket *sock)
sock_set_flag(sk, SOCK_DEAD);
sock_set_flag(sk, SOCK_DESTROY);
break;
+
+ case X25_STATE_5:
+ x25_write_internal(sk, X25_CLEAR_REQUEST);
+ x25_disconnect(sk, 0, 0, 0);
+ __x25_destroy_socket(sk);
+ goto out;
}
sock_orphan(sk);
@@ -672,33 +670,41 @@ out:
return 0;
}
-static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+static int x25_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int addr_len)
{
struct sock *sk = sock->sk;
struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;
int len, i, rc = 0;
- if (!sock_flag(sk, SOCK_ZAPPED) ||
- addr_len != sizeof(struct sockaddr_x25) ||
- addr->sx25_family != AF_X25) {
+ if (addr_len != sizeof(struct sockaddr_x25) ||
+ addr->sx25_family != AF_X25 ||
+ strnlen(addr->sx25_addr.x25_addr, X25_ADDR_LEN) == X25_ADDR_LEN) {
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;
+ /* check for the null_x25_address */
+ if (strcmp(addr->sx25_addr.x25_addr, null_x25_address.x25_addr)) {
+
+ 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;
+ }
}
}
lock_sock(sk);
- x25_sk(sk)->source_addr = addr->sx25_addr;
- x25_insert_socket(sk);
- sock_reset_flag(sk, SOCK_ZAPPED);
+ if (sock_flag(sk, SOCK_ZAPPED)) {
+ x25_sk(sk)->source_addr = addr->sx25_addr;
+ x25_insert_socket(sk);
+ sock_reset_flag(sk, SOCK_ZAPPED);
+ } else {
+ rc = -EINVAL;
+ }
release_sock(sk);
- SOCK_DEBUG(sk, "x25_bind: socket is bound\n");
+ net_dbg_ratelimited("x25_bind: socket is bound\n");
out:
return rc;
}
@@ -719,6 +725,11 @@ static int x25_wait_for_connection_establishment(struct sock *sk)
sk->sk_socket->state = SS_UNCONNECTED;
break;
}
+ rc = -ENOTCONN;
+ if (sk->sk_state == TCP_CLOSE) {
+ sk->sk_socket->state = SS_UNCONNECTED;
+ break;
+ }
rc = 0;
if (sk->sk_state != TCP_ESTABLISHED) {
release_sock(sk);
@@ -732,7 +743,7 @@ static int x25_wait_for_connection_establishment(struct sock *sk)
return rc;
}
-static int x25_connect(struct socket *sock, struct sockaddr *uaddr,
+static int x25_connect(struct socket *sock, struct sockaddr_unsized *uaddr,
int addr_len, int flags)
{
struct sock *sk = sock->sk;
@@ -757,12 +768,17 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr,
if (sk->sk_state == TCP_ESTABLISHED)
goto out;
+ rc = -EALREADY; /* Do nothing if call is already in progress */
+ if (sk->sk_state == TCP_SYN_SENT)
+ goto out;
+
sk->sk_state = TCP_CLOSE;
sock->state = SS_UNCONNECTED;
rc = -EINVAL;
if (addr_len != sizeof(struct sockaddr_x25) ||
- addr->sx25_family != AF_X25)
+ addr->sx25_family != AF_X25 ||
+ strnlen(addr->sx25_addr.x25_addr, X25_ADDR_LEN) == X25_ADDR_LEN)
goto out;
rc = -ENETUNREACH;
@@ -803,7 +819,7 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr,
/* Now the loop */
rc = -EINPROGRESS;
if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
- goto out_put_neigh;
+ goto out;
rc = x25_wait_for_connection_establishment(sk);
if (rc)
@@ -812,8 +828,13 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr,
sock->state = SS_CONNECTED;
rc = 0;
out_put_neigh:
- if (rc)
+ if (rc && x25->neighbour) {
+ read_lock_bh(&x25_list_lock);
x25_neigh_put(x25->neighbour);
+ x25->neighbour = NULL;
+ read_unlock_bh(&x25_list_lock);
+ x25->state = X25_STATE_0;
+ }
out_put_route:
x25_route_put(rt);
out:
@@ -850,7 +871,8 @@ static int x25_wait_for_data(struct sock *sk, long timeout)
return rc;
}
-static int x25_accept(struct socket *sock, struct socket *newsock, int flags)
+static int x25_accept(struct socket *sock, struct socket *newsock,
+ struct proto_accept_arg *arg)
{
struct sock *sk = sock->sk;
struct sock *newsk;
@@ -869,7 +891,7 @@ static int x25_accept(struct socket *sock, struct socket *newsock, int flags)
if (sk->sk_state != TCP_LISTEN)
goto out2;
- rc = x25_wait_for_data(sk, sk->sk_rcvtimeo);
+ rc = x25_wait_for_data(sk, READ_ONCE(sk->sk_rcvtimeo));
if (rc)
goto out2;
skb = skb_dequeue(&sk->sk_receive_queue);
@@ -882,7 +904,7 @@ static int x25_accept(struct socket *sock, struct socket *newsock, int flags)
/* Now attach up the new socket */
skb->sk = NULL;
kfree_skb(skb);
- sk->sk_ack_backlog--;
+ sk_acceptq_removed(sk);
newsock->state = SS_CONNECTED;
rc = 0;
out2:
@@ -892,7 +914,7 @@ out:
}
static int x25_getname(struct socket *sock, struct sockaddr *uaddr,
- int *uaddr_len, int peer)
+ int peer)
{
struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)uaddr;
struct sock *sk = sock->sk;
@@ -909,7 +931,7 @@ static int x25_getname(struct socket *sock, struct sockaddr *uaddr,
sx25->sx25_addr = x25->source_addr;
sx25->sx25_family = AF_X25;
- *uaddr_len = sizeof(*sx25);
+ rc = sizeof(*sx25);
out:
return rc;
@@ -1007,7 +1029,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
/*
* current neighbour/link might impose additional limits
- * on certain facilties
+ * on certain facilities
*/
x25_limit_facilities(&facilities, nb);
@@ -1031,6 +1053,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
makex25->lci = lci;
makex25->dest_addr = dest_addr;
makex25->source_addr = source_addr;
+ x25_neigh_hold(nb);
makex25->neighbour = nb;
makex25->facilities = facilities;
makex25->dte_facilities= dte_facilities;
@@ -1045,6 +1068,8 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
if (test_bit(X25_ACCPT_APPRV_FLAG, &makex25->flags)) {
x25_write_internal(make, X25_CALL_ACCEPTED);
makex25->state = X25_STATE_3;
+ } else {
+ makex25->state = X25_STATE_5;
}
/*
@@ -1053,7 +1078,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
skb_copy_from_linear_data(skb, makex25->calluserdata.cuddata, skb->len);
makex25->calluserdata.cudlength = skb->len;
- sk->sk_ack_backlog++;
+ sk_acceptq_added(sk);
x25_insert_socket(make);
@@ -1062,7 +1087,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
x25_start_heartbeat(make);
if (!sock_flag(sk, SOCK_DEAD))
- sk->sk_data_ready(sk, skb->len);
+ sk->sk_data_ready(sk);
rc = 1;
sock_put(sk);
out:
@@ -1075,12 +1100,11 @@ out_clear_request:
goto out;
}
-static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t len)
+static int x25_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
{
struct sock *sk = sock->sk;
struct x25_sock *x25 = x25_sk(sk);
- struct sockaddr_x25 *usx25 = (struct sockaddr_x25 *)msg->msg_name;
+ DECLARE_SOCKADDR(struct sockaddr_x25 *, usx25, msg->msg_name);
struct sockaddr_x25 sx25;
struct sk_buff *skb;
unsigned char *asmptr;
@@ -1141,10 +1165,10 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
goto out;
}
- SOCK_DEBUG(sk, "x25_sendmsg: sendto: Addresses built.\n");
+ net_dbg_ratelimited("x25_sendmsg: sendto: Addresses built.\n");
/* Build a packet */
- SOCK_DEBUG(sk, "x25_sendmsg: sendto: building packet.\n");
+ net_dbg_ratelimited("x25_sendmsg: sendto: building packet.\n");
if ((msg->msg_flags & MSG_OOB) && len > 32)
len = 32;
@@ -1163,12 +1187,12 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
/*
* Put the data on the end
*/
- SOCK_DEBUG(sk, "x25_sendmsg: Copying user data\n");
+ net_dbg_ratelimited("x25_sendmsg: Copying user data\n");
skb_reset_transport_header(skb);
skb_put(skb, len);
- rc = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len);
+ rc = memcpy_from_msg(skb_transport_header(skb), msg, len);
if (rc)
goto out_kfree_skb;
@@ -1187,7 +1211,7 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
/*
* Push down the X.25 header
*/
- SOCK_DEBUG(sk, "x25_sendmsg: Building X.25 Header.\n");
+ net_dbg_ratelimited("x25_sendmsg: Building X.25 Header.\n");
if (msg->msg_flags & MSG_OOB) {
if (x25->neighbour->extended) {
@@ -1221,8 +1245,8 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
skb->data[0] |= X25_Q_BIT;
}
- SOCK_DEBUG(sk, "x25_sendmsg: Built header.\n");
- SOCK_DEBUG(sk, "x25_sendmsg: Transmitting buffer\n");
+ net_dbg_ratelimited("x25_sendmsg: Built header.\n");
+ net_dbg_ratelimited("x25_sendmsg: Transmitting buffer\n");
rc = -ENOTCONN;
if (sk->sk_state != TCP_ESTABLISHED)
@@ -1250,13 +1274,12 @@ out_kfree_skb:
}
-static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t size,
+static int x25_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
int flags)
{
struct sock *sk = sock->sk;
struct x25_sock *x25 = x25_sk(sk);
- struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name;
+ DECLARE_SOCKADDR(struct sockaddr_x25 *, sx25, msg->msg_name);
size_t copied;
int qbit, header_len;
struct sk_buff *skb;
@@ -1303,8 +1326,7 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
} else {
/* Now we can treat all alike */
release_sock(sk);
- skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
- flags & MSG_DONTWAIT, &rc);
+ skb = skb_recv_datagram(sk, flags, &rc);
lock_sock(sk);
if (!skb)
goto out;
@@ -1333,17 +1355,16 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
/* Currently, each datagram always contains a complete record */
msg->msg_flags |= MSG_EOR;
- rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ rc = skb_copy_datagram_msg(skb, 0, msg, copied);
if (rc)
goto out_free_dgram;
if (sx25) {
sx25->sx25_family = AF_X25;
sx25->sx25_addr = x25->dest_addr;
+ msg->msg_namelen = sizeof(*sx25);
}
- msg->msg_namelen = sizeof(struct sockaddr_x25);
-
x25_check_rbuf(sk);
rc = copied;
out_free_dgram:
@@ -1387,18 +1408,6 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
break;
}
- case SIOCGSTAMP:
- rc = -EINVAL;
- if (sk)
- rc = sock_get_timestamp(sk,
- (struct timeval __user *)argp);
- break;
- case SIOCGSTAMPNS:
- rc = -EINVAL;
- if (sk)
- rc = sock_get_timestampns(sk,
- (struct timespec __user *)argp);
- break;
case SIOCGIFADDR:
case SIOCSIFADDR:
case SIOCGIFDSTADDR:
@@ -1501,12 +1510,8 @@ out_fac_release:
goto out_dtefac_release;
if (dtefacs.calling_len > X25_MAX_AE_LEN)
goto out_dtefac_release;
- if (dtefacs.calling_ae == NULL)
- goto out_dtefac_release;
if (dtefacs.called_len > X25_MAX_AE_LEN)
goto out_dtefac_release;
- if (dtefacs.called_ae == NULL)
- goto out_dtefac_release;
x25->dte_facilities = dtefacs;
rc = 0;
out_dtefac_release:
@@ -1674,8 +1679,6 @@ 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) {
@@ -1683,18 +1686,6 @@ static int compat_x25_ioctl(struct socket *sock, unsigned int cmd,
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 SIOCGSTAMPNS:
- rc = -EINVAL;
- if (sk)
- rc = compat_sock_get_timestampns(sk,
- (struct timespec __user*)argp);
- break;
case SIOCGIFADDR:
case SIOCSIFADDR:
case SIOCGIFDSTADDR:
@@ -1758,6 +1749,7 @@ static const struct proto_ops x25_proto_ops = {
#ifdef CONFIG_COMPAT
.compat_ioctl = compat_x25_ioctl,
#endif
+ .gettstamp = sock_gettstamp,
.listen = x25_listen,
.shutdown = sock_no_shutdown,
.setsockopt = x25_setsockopt,
@@ -1765,7 +1757,6 @@ static const struct proto_ops x25_proto_ops = {
.sendmsg = x25_sendmsg,
.recvmsg = x25_recvmsg,
.mmap = sock_no_mmap,
- .sendpage = sock_no_sendpage,
};
static struct packet_type x25_packet_type __read_mostly = {
@@ -1783,10 +1774,15 @@ void x25_kill_by_neigh(struct x25_neigh *nb)
write_lock_bh(&x25_list_lock);
- sk_for_each(s, &x25_list)
- if (x25_sk(s)->neighbour == nb)
+ sk_for_each(s, &x25_list) {
+ if (x25_sk(s)->neighbour == nb) {
+ write_unlock_bh(&x25_list_lock);
+ lock_sock(s);
x25_disconnect(s, ENETUNREACH, 0, 0);
-
+ release_sock(s);
+ write_lock_bh(&x25_list_lock);
+ }
+ }
write_unlock_bh(&x25_list_lock);
/* Remove any related forwards */
@@ -1795,32 +1791,40 @@ void x25_kill_by_neigh(struct x25_neigh *nb)
static int __init x25_init(void)
{
- int rc = proto_register(&x25_proto, 0);
+ int rc;
- if (rc != 0)
+ rc = proto_register(&x25_proto, 0);
+ if (rc)
goto out;
rc = sock_register(&x25_family_ops);
- if (rc != 0)
+ if (rc)
goto out_proto;
dev_add_pack(&x25_packet_type);
rc = register_netdevice_notifier(&x25_dev_notifier);
- if (rc != 0)
+ if (rc)
goto out_sock;
- printk(KERN_INFO "X.25 for Linux Version 0.2\n");
+ rc = x25_register_sysctl();
+ if (rc)
+ goto out_dev;
- x25_register_sysctl();
rc = x25_proc_init();
- if (rc != 0)
- goto out_dev;
+ if (rc)
+ goto out_sysctl;
+
+ pr_info("Linux Version 0.2\n");
+
out:
return rc;
+out_sysctl:
+ x25_unregister_sysctl();
out_dev:
unregister_netdevice_notifier(&x25_dev_notifier);
out_sock:
+ dev_remove_pack(&x25_packet_type);
sock_unregister(AF_X25);
out_proto:
proto_unregister(&x25_proto);