aboutsummaryrefslogtreecommitdiff
path: root/net/x25
diff options
context:
space:
mode:
Diffstat (limited to 'net/x25')
-rw-r--r--net/x25/Kconfig8
-rw-r--r--net/x25/af_x25.c594
-rw-r--r--net/x25/sysctl_net_x25.c10
-rw-r--r--net/x25/x25_dev.c68
-rw-r--r--net/x25/x25_facilities.c60
-rw-r--r--net/x25/x25_forward.c9
-rw-r--r--net/x25/x25_in.c167
-rw-r--r--net/x25/x25_link.c90
-rw-r--r--net/x25/x25_out.c7
-rw-r--r--net/x25/x25_proc.c48
-rw-r--r--net/x25/x25_route.c4
-rw-r--r--net/x25/x25_subr.c96
12 files changed, 616 insertions, 545 deletions
diff --git a/net/x25/Kconfig b/net/x25/Kconfig
index 2196e55e4f6..e2fa133f9fb 100644
--- a/net/x25/Kconfig
+++ b/net/x25/Kconfig
@@ -3,9 +3,7 @@
#
config X25
- tristate "CCITT X.25 Packet Layer (EXPERIMENTAL)"
- depends on EXPERIMENTAL
- depends on BKL # should be fixable
+ tristate "CCITT X.25 Packet Layer"
---help---
X.25 is a set of standardized network protocols, similar in scope to
frame relay; the one physical line from your box to the X.25 network
@@ -18,8 +16,8 @@ config X25
if you want that) and the lower level data link layer protocol LAPB
(say Y to "LAPB Data Link Driver" below if you want that).
- You can read more about X.25 at <http://www.sangoma.com/x25.htm> and
- <http://www.cisco.com/univercd/cc/td/doc/product/software/ios11/cbook/cx25.htm>.
+ You can read more about X.25 at <http://www.sangoma.com/tutorials/x25/> and
+ <http://docwiki.cisco.com/wiki/X.25>.
Information about X.25 for Linux is contained in the files
<file:Documentation/networking/x25.txt> and
<file:Documentation/networking/x25-iface.txt>.
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index ad96ee90fe2..5ad4418ef09 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -35,12 +35,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/smp_lock.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/net.h>
@@ -92,7 +93,7 @@ int x25_parse_address_block(struct sk_buff *skb,
int needed;
int rc;
- if (skb->len < 1) {
+ if (!pskb_may_pull(skb, 1)) {
/* packet has no address block */
rc = 0;
goto empty;
@@ -101,7 +102,7 @@ int x25_parse_address_block(struct sk_buff *skb,
len = *skb->data;
needed = 1 + (len >> 4) + (len & 0x0f);
- if (skb->len < needed) {
+ if (!pskb_may_pull(skb, needed)) {
/* packet is too short to hold the addresses it claims
to hold */
rc = -1;
@@ -209,11 +210,10 @@ static void x25_remove_socket(struct sock *sk)
static void x25_kill_by_device(struct net_device *dev)
{
struct sock *s;
- struct hlist_node *node;
write_lock_bh(&x25_list_lock);
- sk_for_each(s, node, &x25_list)
+ sk_for_each(s, &x25_list)
if (x25_sk(s)->neighbour && x25_sk(s)->neighbour->dev == dev)
x25_disconnect(s, ENETUNREACH, 0, 0);
@@ -226,33 +226,33 @@ static void x25_kill_by_device(struct net_device *dev)
static int x25_device_event(struct notifier_block *this, unsigned long event,
void *ptr)
{
- struct net_device *dev = ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct x25_neigh *nb;
if (!net_eq(dev_net(dev), &init_net))
return NOTIFY_DONE;
if (dev->type == ARPHRD_X25
-#if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
+#if IS_ENABLED(CONFIG_LLC)
|| dev->type == ARPHRD_ETHER
#endif
) {
switch (event) {
- case NETDEV_UP:
- x25_link_device_up(dev);
- break;
- case NETDEV_GOING_DOWN:
- nb = x25_get_neigh(dev);
- if (nb) {
- x25_terminate_link(nb);
- x25_neigh_put(nb);
- }
- break;
- case NETDEV_DOWN:
- x25_kill_by_device(dev);
- x25_route_device_down(dev);
- x25_link_device_down(dev);
- break;
+ case NETDEV_UP:
+ x25_link_device_up(dev);
+ break;
+ case NETDEV_GOING_DOWN:
+ nb = x25_get_neigh(dev);
+ if (nb) {
+ x25_terminate_link(nb);
+ x25_neigh_put(nb);
+ }
+ break;
+ case NETDEV_DOWN:
+ x25_kill_by_device(dev);
+ x25_route_device_down(dev);
+ x25_link_device_down(dev);
+ break;
}
}
@@ -281,12 +281,11 @@ static struct sock *x25_find_listener(struct x25_address *addr,
{
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)
+ sk_for_each(s, &x25_list)
if ((!strcmp(addr->x25_addr,
x25_sk(s)->source_addr.x25_addr) ||
!strcmp(addr->x25_addr,
@@ -296,7 +295,8 @@ static struct sock *x25_find_listener(struct x25_address *addr,
* 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 (x25_sk(s)->cudmatchlength > 0 &&
+ skb->len >= x25_sk(s)->cudmatchlength) {
if((memcmp(x25_sk(s)->calluserdata.cuddata,
skb->data,
x25_sk(s)->cudmatchlength)) == 0) {
@@ -323,9 +323,8 @@ found:
static struct sock *__x25_find_socket(unsigned int lci, struct x25_neigh *nb)
{
struct sock *s;
- struct hlist_node *node;
- sk_for_each(s, node, &x25_list)
+ sk_for_each(s, &x25_list)
if (x25_sk(s)->lci == lci && x25_sk(s)->neighbour == nb) {
sock_hold(s);
goto found;
@@ -432,15 +431,6 @@ void x25_destroy_socket_from_timer(struct sock *sk)
sock_put(sk);
}
-static void x25_destroy_socket(struct sock *sk)
-{
- sock_hold(sk);
- lock_sock(sk);
- __x25_destroy_socket(sk);
- release_sock(sk);
- sock_put(sk);
-}
-
/*
* Handling for system calls applied via the various interfaces to a
* X.25 socket object.
@@ -647,18 +637,19 @@ static int x25_release(struct socket *sock)
struct sock *sk = sock->sk;
struct x25_sock *x25;
- lock_kernel();
if (!sk)
- goto out;
+ return 0;
x25 = x25_sk(sk);
+ sock_hold(sk);
+ lock_sock(sk);
switch (x25->state) {
case X25_STATE_0:
case X25_STATE_2:
x25_disconnect(sk, 0, 0, 0);
- x25_destroy_socket(sk);
+ __x25_destroy_socket(sk);
goto out;
case X25_STATE_1:
@@ -678,7 +669,8 @@ static int x25_release(struct socket *sock)
sock_orphan(sk);
out:
- unlock_kernel();
+ release_sock(sk);
+ sock_put(sk);
return 0;
}
@@ -959,14 +951,27 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
*
* Facilities length is mandatory in call request packets
*/
- if (skb->len < 1)
+ if (!pskb_may_pull(skb, 1))
goto out_clear_request;
len = skb->data[0] + 1;
- if (skb->len < len)
+ if (!pskb_may_pull(skb, len))
goto out_clear_request;
skb_pull(skb,len);
/*
+ * Ensure that the amount of call user data is valid.
+ */
+ if (skb->len > X25_MAX_CUD_LEN)
+ goto out_clear_request;
+
+ /*
+ * Get all the call user data so it can be used in
+ * x25_find_listener and skb_copy_from_linear_data up ahead.
+ */
+ if (!pskb_may_pull(skb, skb->len))
+ goto out_clear_request;
+
+ /*
* Find a listener for the particular address/cud pair.
*/
sk = x25_find_listener(&source_addr,skb);
@@ -1059,7 +1064,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:
@@ -1077,7 +1082,7 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
{
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;
@@ -1085,7 +1090,7 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
size_t size;
int qbit = 0, rc = -EINVAL;
- lock_kernel();
+ lock_sock(sk);
if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_OOB|MSG_EOR|MSG_CMSG_COMPAT))
goto out;
@@ -1148,7 +1153,9 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
size = len + X25_MAX_L2_LEN + X25_EXT_MIN_LEN;
+ release_sock(sk);
skb = sock_alloc_send_skb(sk, size, noblock, &rc);
+ lock_sock(sk);
if (!skb)
goto out;
X25_SKB_CB(skb)->flags = msg->msg_flags;
@@ -1172,6 +1179,9 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
* byte of the user data is the logical value of the Q Bit.
*/
if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) {
+ if (!pskb_may_pull(skb, 1))
+ goto out_kfree_skb;
+
qbit = skb->data[0];
skb_pull(skb, 1);
}
@@ -1231,26 +1241,10 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
len++;
}
- /*
- * lock_sock() is currently only used to serialize this x25_kick()
- * against input-driven x25_kick() calls. It currently only blocks
- * incoming packets for this socket and does not protect against
- * any other socket state changes and is not called from anywhere
- * else. As x25_kick() cannot block and as long as all socket
- * operations are BKL-wrapped, we don't need take to care about
- * purging the backlog queue in x25_release().
- *
- * Using lock_sock() to protect all socket operations entirely
- * (and making the whole x25 stack SMP aware) unfortunately would
- * require major changes to {send,recv}msg and skb allocation methods.
- * -> 2.5 ;)
- */
- lock_sock(sk);
x25_kick(sk);
- release_sock(sk);
rc = len;
out:
- unlock_kernel();
+ release_sock(sk);
return rc;
out_kfree_skb:
kfree_skb(skb);
@@ -1264,14 +1258,21 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
{
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;
+ int qbit, header_len;
struct sk_buff *skb;
unsigned char *asmptr;
int rc = -ENOTCONN;
- lock_kernel();
+ lock_sock(sk);
+
+ if (x25->neighbour == NULL)
+ goto out;
+
+ header_len = x25->neighbour->extended ?
+ X25_EXT_MIN_LEN : X25_STD_MIN_LEN;
+
/*
* This works for seqpacket too. The receiver has ordered the queue for
* us! We do one quick check first though
@@ -1287,6 +1288,9 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
skb = skb_dequeue(&x25->interrupt_in_queue);
+ if (!pskb_may_pull(skb, X25_STD_MIN_LEN))
+ goto out_free_dgram;
+
skb_pull(skb, X25_STD_MIN_LEN);
/*
@@ -1300,15 +1304,19 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
msg->msg_flags |= MSG_OOB;
} else {
/* Now we can treat all alike */
+ release_sock(sk);
skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
flags & MSG_DONTWAIT, &rc);
+ lock_sock(sk);
if (!skb)
goto out;
+ if (!pskb_may_pull(skb, header_len))
+ goto out_free_dgram;
+
qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT;
- skb_pull(skb, x25->neighbour->extended ?
- X25_EXT_MIN_LEN : X25_STD_MIN_LEN);
+ skb_pull(skb, header_len);
if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) {
asmptr = skb_push(skb, 1);
@@ -1334,18 +1342,15 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
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);
-
- lock_sock(sk);
x25_check_rbuf(sk);
- release_sock(sk);
rc = copied;
out_free_dgram:
skb_free_datagram(sk, skb);
out:
- unlock_kernel();
+ release_sock(sk);
return rc;
}
@@ -1358,256 +1363,254 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
int rc;
switch (cmd) {
- case TIOCOUTQ: {
- int amount;
+ case TIOCOUTQ: {
+ int amount;
- amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
- if (amount < 0)
- amount = 0;
- rc = put_user(amount, (unsigned int __user *)argp);
- break;
- }
+ amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
+ if (amount < 0)
+ amount = 0;
+ rc = put_user(amount, (unsigned int __user *)argp);
+ break;
+ }
- case TIOCINQ: {
- struct sk_buff *skb;
- int amount = 0;
- /*
- * These two are safe on a single CPU system as
- * only user tasks fiddle here
- */
- lock_sock(sk);
- if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL)
- amount = skb->len;
- release_sock(sk);
- rc = put_user(amount, (unsigned int __user *)argp);
- break;
- }
+ case TIOCINQ: {
+ struct sk_buff *skb;
+ int amount = 0;
+ /*
+ * These two are safe on a single CPU system as
+ * only user tasks fiddle here
+ */
+ lock_sock(sk);
+ if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL)
+ amount = skb->len;
+ release_sock(sk);
+ rc = put_user(amount, (unsigned int __user *)argp);
+ break;
+ }
- case SIOCGSTAMP:
- rc = -EINVAL;
- if (sk)
- rc = sock_get_timestamp(sk,
+ 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:
+ 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;
- case SIOCGSTAMPNS:
- rc = -EINVAL;
- if (sk)
- rc = sock_get_timestampns(sk,
- (struct timespec __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 = x25_subscr_ioctl(cmd, argp);
- break;
- case SIOCX25SSUBSCRIP:
- rc = -EPERM;
- if (!capable(CAP_NET_ADMIN))
- break;
- rc = x25_subscr_ioctl(cmd, argp);
- break;
- case SIOCX25GFACILITIES: {
- lock_sock(sk);
- rc = copy_to_user(argp, &x25->facilities,
- sizeof(x25->facilities))
- ? -EFAULT : 0;
- release_sock(sk);
+ rc = x25_route_ioctl(cmd, argp);
+ break;
+ case SIOCX25GSUBSCRIP:
+ rc = x25_subscr_ioctl(cmd, argp);
+ break;
+ case SIOCX25SSUBSCRIP:
+ rc = -EPERM;
+ if (!capable(CAP_NET_ADMIN))
break;
- }
+ rc = x25_subscr_ioctl(cmd, argp);
+ break;
+ case SIOCX25GFACILITIES: {
+ lock_sock(sk);
+ rc = copy_to_user(argp, &x25->facilities,
+ sizeof(x25->facilities))
+ ? -EFAULT : 0;
+ release_sock(sk);
+ break;
+ }
- case SIOCX25SFACILITIES: {
- struct x25_facilities facilities;
- rc = -EFAULT;
- if (copy_from_user(&facilities, argp,
- sizeof(facilities)))
- break;
- rc = -EINVAL;
- lock_sock(sk);
- if (sk->sk_state != TCP_LISTEN &&
- sk->sk_state != TCP_CLOSE)
- goto out_fac_release;
- if (facilities.pacsize_in < X25_PS16 ||
- facilities.pacsize_in > X25_PS4096)
- goto out_fac_release;
- if (facilities.pacsize_out < X25_PS16 ||
- facilities.pacsize_out > X25_PS4096)
- goto out_fac_release;
- if (facilities.winsize_in < 1 ||
- facilities.winsize_in > 127)
+ case SIOCX25SFACILITIES: {
+ struct x25_facilities facilities;
+ rc = -EFAULT;
+ if (copy_from_user(&facilities, argp, sizeof(facilities)))
+ break;
+ rc = -EINVAL;
+ lock_sock(sk);
+ if (sk->sk_state != TCP_LISTEN &&
+ sk->sk_state != TCP_CLOSE)
+ goto out_fac_release;
+ if (facilities.pacsize_in < X25_PS16 ||
+ facilities.pacsize_in > X25_PS4096)
+ goto out_fac_release;
+ if (facilities.pacsize_out < X25_PS16 ||
+ facilities.pacsize_out > X25_PS4096)
+ goto out_fac_release;
+ if (facilities.winsize_in < 1 ||
+ facilities.winsize_in > 127)
+ goto out_fac_release;
+ if (facilities.throughput) {
+ int out = facilities.throughput & 0xf0;
+ int in = facilities.throughput & 0x0f;
+ if (!out)
+ facilities.throughput |=
+ X25_DEFAULT_THROUGHPUT << 4;
+ else if (out < 0x30 || out > 0xD0)
goto out_fac_release;
- if (facilities.throughput) {
- int out = facilities.throughput & 0xf0;
- int in = facilities.throughput & 0x0f;
- if (!out)
- facilities.throughput |=
- X25_DEFAULT_THROUGHPUT << 4;
- else if (out < 0x30 || out > 0xD0)
- goto out_fac_release;
- if (!in)
- facilities.throughput |=
- X25_DEFAULT_THROUGHPUT;
- else if (in < 0x03 || in > 0x0D)
- goto out_fac_release;
- }
- if (facilities.reverse &&
- (facilities.reverse & 0x81) != 0x81)
+ if (!in)
+ facilities.throughput |=
+ X25_DEFAULT_THROUGHPUT;
+ else if (in < 0x03 || in > 0x0D)
goto out_fac_release;
- x25->facilities = facilities;
- rc = 0;
-out_fac_release:
- release_sock(sk);
- break;
- }
-
- case SIOCX25GDTEFACILITIES: {
- lock_sock(sk);
- rc = copy_to_user(argp, &x25->dte_facilities,
- sizeof(x25->dte_facilities));
- release_sock(sk);
- if (rc)
- rc = -EFAULT;
- break;
}
+ if (facilities.reverse &&
+ (facilities.reverse & 0x81) != 0x81)
+ goto out_fac_release;
+ x25->facilities = facilities;
+ rc = 0;
+out_fac_release:
+ release_sock(sk);
+ break;
+ }
- case SIOCX25SDTEFACILITIES: {
- struct x25_dte_facilities dtefacs;
+ case SIOCX25GDTEFACILITIES: {
+ lock_sock(sk);
+ rc = copy_to_user(argp, &x25->dte_facilities,
+ sizeof(x25->dte_facilities));
+ release_sock(sk);
+ if (rc)
rc = -EFAULT;
- if (copy_from_user(&dtefacs, argp, sizeof(dtefacs)))
- break;
- rc = -EINVAL;
- lock_sock(sk);
- if (sk->sk_state != TCP_LISTEN &&
- sk->sk_state != TCP_CLOSE)
- 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:
- release_sock(sk);
- break;
- }
+ break;
+ }
- case SIOCX25GCALLUSERDATA: {
- lock_sock(sk);
- rc = copy_to_user(argp, &x25->calluserdata,
- sizeof(x25->calluserdata))
- ? -EFAULT : 0;
- release_sock(sk);
+ case SIOCX25SDTEFACILITIES: {
+ struct x25_dte_facilities dtefacs;
+ rc = -EFAULT;
+ if (copy_from_user(&dtefacs, argp, sizeof(dtefacs)))
break;
- }
+ rc = -EINVAL;
+ lock_sock(sk);
+ if (sk->sk_state != TCP_LISTEN &&
+ sk->sk_state != TCP_CLOSE)
+ 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:
+ release_sock(sk);
+ break;
+ }
- case SIOCX25SCALLUSERDATA: {
- struct x25_calluserdata calluserdata;
+ case SIOCX25GCALLUSERDATA: {
+ lock_sock(sk);
+ rc = copy_to_user(argp, &x25->calluserdata,
+ sizeof(x25->calluserdata))
+ ? -EFAULT : 0;
+ release_sock(sk);
+ break;
+ }
- rc = -EFAULT;
- if (copy_from_user(&calluserdata, argp,
- sizeof(calluserdata)))
- break;
- rc = -EINVAL;
- if (calluserdata.cudlength > X25_MAX_CUD_LEN)
- break;
- lock_sock(sk);
- x25->calluserdata = calluserdata;
- release_sock(sk);
- rc = 0;
- break;
- }
+ case SIOCX25SCALLUSERDATA: {
+ struct x25_calluserdata calluserdata;
- case SIOCX25GCAUSEDIAG: {
- lock_sock(sk);
- rc = copy_to_user(argp, &x25->causediag,
- sizeof(x25->causediag))
- ? -EFAULT : 0;
- release_sock(sk);
+ rc = -EFAULT;
+ if (copy_from_user(&calluserdata, argp, sizeof(calluserdata)))
break;
- }
+ rc = -EINVAL;
+ if (calluserdata.cudlength > X25_MAX_CUD_LEN)
+ break;
+ lock_sock(sk);
+ x25->calluserdata = calluserdata;
+ release_sock(sk);
+ rc = 0;
+ break;
+ }
- case SIOCX25SCAUSEDIAG: {
- struct x25_causediag causediag;
- rc = -EFAULT;
- if (copy_from_user(&causediag, argp, sizeof(causediag)))
- break;
- lock_sock(sk);
- x25->causediag = causediag;
- release_sock(sk);
- rc = 0;
+ case SIOCX25GCAUSEDIAG: {
+ lock_sock(sk);
+ rc = copy_to_user(argp, &x25->causediag, sizeof(x25->causediag))
+ ? -EFAULT : 0;
+ release_sock(sk);
+ break;
+ }
+
+ case SIOCX25SCAUSEDIAG: {
+ struct x25_causediag causediag;
+ rc = -EFAULT;
+ if (copy_from_user(&causediag, argp, sizeof(causediag)))
break;
+ lock_sock(sk);
+ x25->causediag = causediag;
+ release_sock(sk);
+ rc = 0;
+ break;
- }
+ }
- case SIOCX25SCUDMATCHLEN: {
- struct x25_subaddr sub_addr;
- rc = -EINVAL;
- lock_sock(sk);
- if(sk->sk_state != TCP_CLOSE)
- goto out_cud_release;
- rc = -EFAULT;
- if (copy_from_user(&sub_addr, argp,
- sizeof(sub_addr)))
- goto out_cud_release;
- rc = -EINVAL;
- if(sub_addr.cudmatchlength > X25_MAX_CUD_LEN)
- goto out_cud_release;
- x25->cudmatchlength = sub_addr.cudmatchlength;
- rc = 0;
+ case SIOCX25SCUDMATCHLEN: {
+ struct x25_subaddr sub_addr;
+ rc = -EINVAL;
+ lock_sock(sk);
+ if(sk->sk_state != TCP_CLOSE)
+ goto out_cud_release;
+ rc = -EFAULT;
+ if (copy_from_user(&sub_addr, argp,
+ sizeof(sub_addr)))
+ goto out_cud_release;
+ rc = -EINVAL;
+ if (sub_addr.cudmatchlength > X25_MAX_CUD_LEN)
+ goto out_cud_release;
+ x25->cudmatchlength = sub_addr.cudmatchlength;
+ rc = 0;
out_cud_release:
- release_sock(sk);
- break;
- }
+ release_sock(sk);
+ break;
+ }
- case SIOCX25CALLACCPTAPPRV: {
- rc = -EINVAL;
- lock_kernel();
- if (sk->sk_state != TCP_CLOSE)
- break;
+ case SIOCX25CALLACCPTAPPRV: {
+ rc = -EINVAL;
+ lock_sock(sk);
+ if (sk->sk_state == TCP_CLOSE) {
clear_bit(X25_ACCPT_APPRV_FLAG, &x25->flags);
- unlock_kernel();
rc = 0;
- break;
}
+ release_sock(sk);
+ break;
+ }
- case SIOCX25SENDCALLACCPT: {
- rc = -EINVAL;
- lock_kernel();
- if (sk->sk_state != TCP_ESTABLISHED)
- break;
- /* must call accptapprv above */
- if (test_bit(X25_ACCPT_APPRV_FLAG, &x25->flags))
- break;
- x25_write_internal(sk, X25_CALL_ACCEPTED);
- x25->state = X25_STATE_3;
- unlock_kernel();
- rc = 0;
- break;
- }
+ case SIOCX25SENDCALLACCPT: {
+ rc = -EINVAL;
+ lock_sock(sk);
+ if (sk->sk_state != TCP_ESTABLISHED)
+ goto out_sendcallaccpt_release;
+ /* must call accptapprv above */
+ if (test_bit(X25_ACCPT_APPRV_FLAG, &x25->flags))
+ goto out_sendcallaccpt_release;
+ x25_write_internal(sk, X25_CALL_ACCEPTED);
+ x25->state = X25_STATE_3;
+ rc = 0;
+out_sendcallaccpt_release:
+ release_sock(sk);
+ break;
+ }
- default:
- rc = -ENOIOCTLCMD;
- break;
+ default:
+ rc = -ENOIOCTLCMD;
+ break;
}
return rc;
@@ -1778,11 +1781,10 @@ static struct notifier_block x25_dev_notifier = {
void x25_kill_by_neigh(struct x25_neigh *nb)
{
struct sock *s;
- struct hlist_node *node;
write_lock_bh(&x25_list_lock);
- sk_for_each(s, node, &x25_list)
+ sk_for_each(s, &x25_list)
if (x25_sk(s)->neighbour == nb)
x25_disconnect(s, ENETUNREACH, 0, 0);
@@ -1809,7 +1811,7 @@ static int __init x25_init(void)
if (rc != 0)
goto out_sock;
- printk(KERN_INFO "X.25 for Linux Version 0.2\n");
+ pr_info("Linux Version 0.2\n");
x25_register_sysctl();
rc = x25_proc_init();
diff --git a/net/x25/sysctl_net_x25.c b/net/x25/sysctl_net_x25.c
index d2efd29f434..43239527a20 100644
--- a/net/x25/sysctl_net_x25.c
+++ b/net/x25/sysctl_net_x25.c
@@ -73,18 +73,12 @@ static struct ctl_table x25_table[] = {
{ 0, },
};
-static struct ctl_path x25_path[] = {
- { .procname = "net", },
- { .procname = "x25", },
- { }
-};
-
void __init x25_register_sysctl(void)
{
- x25_table_header = register_sysctl_paths(x25_path, x25_table);
+ x25_table_header = register_net_sysctl(&init_net, "net/x25", x25_table);
}
void x25_unregister_sysctl(void)
{
- unregister_sysctl_table(x25_table_header);
+ unregister_net_sysctl_table(x25_table_header);
}
diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c
index 9005f6daeab..39231237e1c 100644
--- a/net/x25/x25_dev.c
+++ b/net/x25/x25_dev.c
@@ -17,6 +17,8 @@
* 2000-09-04 Henner Eisen Prevent freeing a dangling skb.
*/
+#define pr_fmt(fmt) "X25: " fmt
+
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
@@ -32,6 +34,9 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)
unsigned short frametype;
unsigned int lci;
+ if (!pskb_may_pull(skb, X25_STD_MIN_LEN))
+ return 0;
+
frametype = skb->data[2];
lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF);
@@ -55,7 +60,7 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)
if (!sock_owned_by_user(sk)) {
queued = x25_process_rx_frame(sk, skb);
} else {
- queued = !sk_add_backlog(sk, skb);
+ queued = !sk_add_backlog(sk, skb, sk->sk_rcvbuf);
}
bh_unlock_sock(sk);
sock_put(sk);
@@ -86,7 +91,7 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)
*/
if (frametype != X25_CLEAR_CONFIRMATION)
- printk(KERN_DEBUG "x25_receive_data(): unknown frame type %2x\n",frametype);
+ pr_debug("x25_receive_data(): unknown frame type %2x\n",frametype);
return 0;
}
@@ -111,10 +116,13 @@ int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev,
*/
nb = x25_get_neigh(dev);
if (!nb) {
- printk(KERN_DEBUG "X.25: unknown neighbour - %s\n", dev->name);
+ pr_debug("unknown neighbour - %s\n", dev->name);
goto drop;
}
+ if (!pskb_may_pull(skb, 1))
+ return 0;
+
switch (skb->data[0]) {
case X25_IFACE_DATA:
@@ -146,21 +154,21 @@ void x25_establish_link(struct x25_neigh *nb)
unsigned char *ptr;
switch (nb->dev->type) {
- case ARPHRD_X25:
- if ((skb = alloc_skb(1, GFP_ATOMIC)) == NULL) {
- printk(KERN_ERR "x25_dev: out of memory\n");
- return;
- }
- ptr = skb_put(skb, 1);
- *ptr = X25_IFACE_CONNECT;
- break;
-
-#if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
- case ARPHRD_ETHER:
+ case ARPHRD_X25:
+ if ((skb = alloc_skb(1, GFP_ATOMIC)) == NULL) {
+ pr_err("x25_dev: out of memory\n");
return;
+ }
+ ptr = skb_put(skb, 1);
+ *ptr = X25_IFACE_CONNECT;
+ break;
+
+#if IS_ENABLED(CONFIG_LLC)
+ case ARPHRD_ETHER:
+ return;
#endif
- default:
- return;
+ default:
+ return;
}
skb->protocol = htons(ETH_P_X25);
@@ -174,7 +182,7 @@ void x25_terminate_link(struct x25_neigh *nb)
struct sk_buff *skb;
unsigned char *ptr;
-#if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
+#if IS_ENABLED(CONFIG_LLC)
if (nb->dev->type == ARPHRD_ETHER)
return;
#endif
@@ -183,7 +191,7 @@ void x25_terminate_link(struct x25_neigh *nb)
skb = alloc_skb(1, GFP_ATOMIC);
if (!skb) {
- printk(KERN_ERR "x25_dev: out of memory\n");
+ pr_err("x25_dev: out of memory\n");
return;
}
@@ -202,19 +210,19 @@ void x25_send_frame(struct sk_buff *skb, struct x25_neigh *nb)
skb_reset_network_header(skb);
switch (nb->dev->type) {
- case ARPHRD_X25:
- dptr = skb_push(skb, 1);
- *dptr = X25_IFACE_DATA;
- break;
-
-#if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
- case ARPHRD_ETHER:
- kfree_skb(skb);
- return;
+ case ARPHRD_X25:
+ dptr = skb_push(skb, 1);
+ *dptr = X25_IFACE_DATA;
+ break;
+
+#if IS_ENABLED(CONFIG_LLC)
+ case ARPHRD_ETHER:
+ kfree_skb(skb);
+ return;
#endif
- default:
- kfree_skb(skb);
- return;
+ default:
+ kfree_skb(skb);
+ return;
}
skb->protocol = htons(ETH_P_X25);
diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c
index 55187c8f642..7ecd04c2136 100644
--- a/net/x25/x25_facilities.c
+++ b/net/x25/x25_facilities.c
@@ -21,20 +21,32 @@
* on response.
*/
+#define pr_fmt(fmt) "X25: " fmt
+
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <net/x25.h>
-/*
- * Parse a set of facilities into the facilities structures. Unrecognised
- * facilities are written to the debug log file.
+/**
+ * x25_parse_facilities - Parse facilities from skb into the facilities structs
+ *
+ * @skb: sk_buff to parse
+ * @facilities: Regular facilities, updated as facilities are found
+ * @dte_facs: ITU DTE facilities, updated as DTE facilities are found
+ * @vc_fac_mask: mask is updated with all facilities found
+ *
+ * Return codes:
+ * -1 - Parsing error, caller should drop call and clean up
+ * 0 - Parse OK, this skb has no facilities
+ * >0 - Parse OK, returns the length of the facilities header
+ *
*/
int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask)
{
- unsigned char *p = skb->data;
+ unsigned char *p;
unsigned int len;
*vc_fac_mask = 0;
@@ -50,19 +62,21 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
memset(dte_facs->called_ae, '\0', sizeof(dte_facs->called_ae));
memset(dte_facs->calling_ae, '\0', sizeof(dte_facs->calling_ae));
- if (skb->len < 1)
+ if (!pskb_may_pull(skb, 1))
return 0;
- len = *p++;
+ len = skb->data[0];
- if (len >= skb->len)
+ if (!pskb_may_pull(skb, 1 + len))
return -1;
+ p = skb->data + 1;
+
while (len > 0) {
switch (*p & X25_FAC_CLASS_MASK) {
case X25_FAC_CLASS_A:
if (len < 2)
- return 0;
+ return -1;
switch (*p) {
case X25_FAC_REVERSE:
if((p[1] & 0x81) == 0x81) {
@@ -97,7 +111,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
case X25_MARKER:
break;
default:
- printk(KERN_DEBUG "X.25: unknown facility "
+ pr_debug("unknown facility "
"%02X, value %02X\n",
p[0], p[1]);
break;
@@ -107,7 +121,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
break;
case X25_FAC_CLASS_B:
if (len < 3)
- return 0;
+ return -1;
switch (*p) {
case X25_FAC_PACKET_SIZE:
facilities->pacsize_in = p[1];
@@ -120,7 +134,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
*vc_fac_mask |= X25_MASK_WINDOW_SIZE;
break;
default:
- printk(KERN_DEBUG "X.25: unknown facility "
+ pr_debug("unknown facility "
"%02X, values %02X, %02X\n",
p[0], p[1], p[2]);
break;
@@ -130,8 +144,8 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
break;
case X25_FAC_CLASS_C:
if (len < 4)
- return 0;
- printk(KERN_DEBUG "X.25: unknown facility %02X, "
+ return -1;
+ pr_debug("unknown facility %02X, "
"values %02X, %02X, %02X\n",
p[0], p[1], p[2], p[3]);
p += 4;
@@ -139,24 +153,28 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
break;
case X25_FAC_CLASS_D:
if (len < p[1] + 2)
- return 0;
+ return -1;
switch (*p) {
case X25_FAC_CALLING_AE:
if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1)
- return 0;
+ return -1;
+ if (p[2] > X25_MAX_AE_LEN)
+ return -1;
dte_facs->calling_len = p[2];
memcpy(dte_facs->calling_ae, &p[3], p[1] - 1);
*vc_fac_mask |= X25_MASK_CALLING_AE;
break;
case X25_FAC_CALLED_AE:
if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1)
- return 0;
+ return -1;
+ if (p[2] > X25_MAX_AE_LEN)
+ return -1;
dte_facs->called_len = p[2];
memcpy(dte_facs->called_ae, &p[3], p[1] - 1);
*vc_fac_mask |= X25_MASK_CALLED_AE;
break;
default:
- printk(KERN_DEBUG "X.25: unknown facility %02X,"
+ pr_debug("unknown facility %02X,"
"length %d\n", p[0], p[1]);
break;
}
@@ -219,7 +237,7 @@ int x25_create_facilities(unsigned char *buffer,
}
if (dte_facs->calling_len && (facil_mask & X25_MASK_CALLING_AE)) {
- unsigned bytecount = (dte_facs->calling_len + 1) >> 1;
+ unsigned int bytecount = (dte_facs->calling_len + 1) >> 1;
*p++ = X25_FAC_CALLING_AE;
*p++ = 1 + bytecount;
*p++ = dte_facs->calling_len;
@@ -228,7 +246,7 @@ int x25_create_facilities(unsigned char *buffer,
}
if (dte_facs->called_len && (facil_mask & X25_MASK_CALLED_AE)) {
- unsigned bytecount = (dte_facs->called_len % 2) ?
+ unsigned int bytecount = (dte_facs->called_len % 2) ?
dte_facs->called_len / 2 + 1 :
dte_facs->called_len / 2;
*p++ = X25_FAC_CALLED_AE;
@@ -325,12 +343,12 @@ void x25_limit_facilities(struct x25_facilities *facilities,
if (!nb->extended) {
if (facilities->winsize_in > 7) {
- printk(KERN_DEBUG "X.25: incoming winsize limited to 7\n");
+ pr_debug("incoming winsize limited to 7\n");
facilities->winsize_in = 7;
}
if (facilities->winsize_out > 7) {
facilities->winsize_out = 7;
- printk( KERN_DEBUG "X.25: outgoing winsize limited to 7\n");
+ pr_debug("outgoing winsize limited to 7\n");
}
}
}
diff --git a/net/x25/x25_forward.c b/net/x25/x25_forward.c
index 25a81079396..cf561f1613e 100644
--- a/net/x25/x25_forward.c
+++ b/net/x25/x25_forward.c
@@ -8,6 +8,9 @@
* History
* 03-01-2007 Added forwarding for x.25 Andrew Hendry
*/
+
+#define pr_fmt(fmt) "X25: " fmt
+
#include <linux/if_arp.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -31,7 +34,7 @@ int x25_forward_call(struct x25_address *dest_addr, struct x25_neigh *from,
goto out_no_route;
if ((neigh_new = x25_get_neigh(rt->dev)) == NULL) {
- /* This shouldnt happen, if it occurs somehow
+ /* This shouldn't happen, if it occurs somehow
* do something sensible
*/
goto out_put_route;
@@ -45,13 +48,13 @@ int x25_forward_call(struct x25_address *dest_addr, struct x25_neigh *from,
}
/* Remote end sending a call request on an already
- * established LCI? It shouldnt happen, just in case..
+ * established LCI? It shouldn't happen, just in case..
*/
read_lock_bh(&x25_forward_list_lock);
list_for_each(entry, &x25_forward_list) {
x25_frwd = list_entry(entry, struct x25_forward, node);
if (x25_frwd->lci == lci) {
- printk(KERN_WARNING "X.25: call request for lci which is already registered!, transmitting but not registering new pair\n");
+ pr_warn("call request for lci which is already registered!, transmitting but not registering new pair\n");
same_lci = 1;
}
}
diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
index f729f022be6..7ac50098a37 100644
--- a/net/x25/x25_in.c
+++ b/net/x25/x25_in.c
@@ -23,6 +23,8 @@
* i-frames.
*/
+#define pr_fmt(fmt) "X25: " fmt
+
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/kernel.h>
@@ -77,7 +79,7 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
skb_set_owner_r(skbn, sk);
skb_queue_tail(&sk->sk_receive_queue, skbn);
if (!sock_flag(sk, SOCK_DEAD))
- sk->sk_data_ready(sk, skbn->len);
+ sk->sk_data_ready(sk);
return 0;
}
@@ -91,59 +93,74 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
{
struct x25_address source_addr, dest_addr;
int len;
+ struct x25_sock *x25 = x25_sk(sk);
switch (frametype) {
- case X25_CALL_ACCEPTED: {
- struct x25_sock *x25 = x25_sk(sk);
-
- x25_stop_timer(sk);
- x25->condition = 0x00;
- x25->vs = 0;
- x25->va = 0;
- x25->vr = 0;
- x25->vl = 0;
- x25->state = X25_STATE_3;
- sk->sk_state = TCP_ESTABLISHED;
- /*
- * Parse the data in the frame.
- */
- skb_pull(skb, X25_STD_MIN_LEN);
-
- len = x25_parse_address_block(skb, &source_addr,
- &dest_addr);
- if (len > 0)
- skb_pull(skb, len);
-
- len = x25_parse_facilities(skb, &x25->facilities,
- &x25->dte_facilities,
- &x25->vc_facil_mask);
- if (len > 0)
- skb_pull(skb, len);
- else
- return -1;
- /*
- * Copy any Call User Data.
- */
- if (skb->len > 0) {
- skb_copy_from_linear_data(skb,
- x25->calluserdata.cuddata,
- skb->len);
- x25->calluserdata.cudlength = skb->len;
- }
- if (!sock_flag(sk, SOCK_DEAD))
- sk->sk_state_change(sk);
- break;
+ case X25_CALL_ACCEPTED: {
+
+ x25_stop_timer(sk);
+ x25->condition = 0x00;
+ x25->vs = 0;
+ x25->va = 0;
+ x25->vr = 0;
+ x25->vl = 0;
+ x25->state = X25_STATE_3;
+ sk->sk_state = TCP_ESTABLISHED;
+ /*
+ * Parse the data in the frame.
+ */
+ if (!pskb_may_pull(skb, X25_STD_MIN_LEN))
+ goto out_clear;
+ skb_pull(skb, X25_STD_MIN_LEN);
+
+ len = x25_parse_address_block(skb, &source_addr,
+ &dest_addr);
+ if (len > 0)
+ skb_pull(skb, len);
+ else if (len < 0)
+ goto out_clear;
+
+ len = x25_parse_facilities(skb, &x25->facilities,
+ &x25->dte_facilities,
+ &x25->vc_facil_mask);
+ if (len > 0)
+ skb_pull(skb, len);
+ else if (len < 0)
+ goto out_clear;
+ /*
+ * Copy any Call User Data.
+ */
+ if (skb->len > 0) {
+ if (skb->len > X25_MAX_CUD_LEN)
+ goto out_clear;
+
+ skb_copy_bits(skb, 0, x25->calluserdata.cuddata,
+ skb->len);
+ x25->calluserdata.cudlength = skb->len;
}
- case X25_CLEAR_REQUEST:
- x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
- x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]);
- break;
+ if (!sock_flag(sk, SOCK_DEAD))
+ sk->sk_state_change(sk);
+ break;
+ }
+ case X25_CLEAR_REQUEST:
+ if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
+ goto out_clear;
- default:
- break;
+ x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
+ x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]);
+ break;
+
+ default:
+ break;
}
return 0;
+
+out_clear:
+ x25_write_internal(sk, X25_CLEAR_REQUEST);
+ x25->state = X25_STATE_2;
+ x25_start_t23timer(sk);
+ return 0;
}
/*
@@ -156,6 +173,9 @@ static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametyp
switch (frametype) {
case X25_CLEAR_REQUEST:
+ if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
+ goto out_clear;
+
x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
break;
@@ -169,6 +189,11 @@ static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametyp
}
return 0;
+
+out_clear:
+ x25_write_internal(sk, X25_CLEAR_REQUEST);
+ x25_start_t23timer(sk);
+ return 0;
}
/*
@@ -198,6 +223,9 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
break;
case X25_CLEAR_REQUEST:
+ if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
+ goto out_clear;
+
x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
break;
@@ -291,11 +319,17 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
break;
default:
- printk(KERN_WARNING "x25: unknown %02X in state 3\n", frametype);
+ pr_warn("unknown %02X in state 3\n", frametype);
break;
}
return queued;
+
+out_clear:
+ x25_write_internal(sk, X25_CLEAR_REQUEST);
+ x25->state = X25_STATE_2;
+ x25_start_t23timer(sk);
+ return 0;
}
/*
@@ -305,13 +339,13 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
*/
static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype)
{
+ struct x25_sock *x25 = x25_sk(sk);
+
switch (frametype) {
case X25_RESET_REQUEST:
x25_write_internal(sk, X25_RESET_CONFIRMATION);
case X25_RESET_CONFIRMATION: {
- struct x25_sock *x25 = x25_sk(sk);
-
x25_stop_timer(sk);
x25->condition = 0x00;
x25->va = 0;
@@ -323,6 +357,9 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp
break;
}
case X25_CLEAR_REQUEST:
+ if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
+ goto out_clear;
+
x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
break;
@@ -332,6 +369,12 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp
}
return 0;
+
+out_clear:
+ x25_write_internal(sk, X25_CLEAR_REQUEST);
+ x25->state = X25_STATE_2;
+ x25_start_t23timer(sk);
+ return 0;
}
/* Higher level upcall for a LAPB frame */
@@ -346,18 +389,18 @@ int x25_process_rx_frame(struct sock *sk, struct sk_buff *skb)
frametype = x25_decode(sk, skb, &ns, &nr, &q, &d, &m);
switch (x25->state) {
- case X25_STATE_1:
- queued = x25_state1_machine(sk, skb, frametype);
- break;
- case X25_STATE_2:
- queued = x25_state2_machine(sk, skb, frametype);
- break;
- case X25_STATE_3:
- queued = x25_state3_machine(sk, skb, frametype, ns, nr, q, d, m);
- break;
- case X25_STATE_4:
- queued = x25_state4_machine(sk, skb, frametype);
- break;
+ case X25_STATE_1:
+ queued = x25_state1_machine(sk, skb, frametype);
+ break;
+ case X25_STATE_2:
+ queued = x25_state2_machine(sk, skb, frametype);
+ break;
+ case X25_STATE_3:
+ queued = x25_state3_machine(sk, skb, frametype, ns, nr, q, d, m);
+ break;
+ case X25_STATE_4:
+ queued = x25_state4_machine(sk, skb, frametype);
+ break;
}
x25_kick(sk);
diff --git a/net/x25/x25_link.c b/net/x25/x25_link.c
index 4c81f6abb65..fd5ffb25873 100644
--- a/net/x25/x25_link.c
+++ b/net/x25/x25_link.c
@@ -21,6 +21,8 @@
* 2000-09-04 Henner Eisen dev_hold() / dev_put() for x25_neigh.
*/
+#define pr_fmt(fmt) "X25: " fmt
+
#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/timer.h>
@@ -76,30 +78,32 @@ void x25_link_control(struct sk_buff *skb, struct x25_neigh *nb,
int confirm;
switch (frametype) {
- case X25_RESTART_REQUEST:
- confirm = !x25_t20timer_pending(nb);
- x25_stop_t20timer(nb);
- nb->state = X25_LINK_STATE_3;
- if (confirm)
- x25_transmit_restart_confirmation(nb);
- break;
-
- case X25_RESTART_CONFIRMATION:
- x25_stop_t20timer(nb);
- nb->state = X25_LINK_STATE_3;
+ case X25_RESTART_REQUEST:
+ confirm = !x25_t20timer_pending(nb);
+ x25_stop_t20timer(nb);
+ nb->state = X25_LINK_STATE_3;
+ if (confirm)
+ x25_transmit_restart_confirmation(nb);
+ break;
+
+ case X25_RESTART_CONFIRMATION:
+ x25_stop_t20timer(nb);
+ nb->state = X25_LINK_STATE_3;
+ break;
+
+ case X25_DIAGNOSTIC:
+ if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 4))
break;
- case X25_DIAGNOSTIC:
- printk(KERN_WARNING "x25: diagnostic #%d - "
- "%02X %02X %02X\n",
- skb->data[3], skb->data[4],
- skb->data[5], skb->data[6]);
- break;
+ pr_warn("diagnostic #%d - %02X %02X %02X\n",
+ skb->data[3], skb->data[4],
+ skb->data[5], skb->data[6]);
+ break;
- default:
- printk(KERN_WARNING "x25: received unknown %02X "
- "with LCI 000\n", frametype);
- break;
+ default:
+ pr_warn("received unknown %02X with LCI 000\n",
+ frametype);
+ break;
}
if (nb->state == X25_LINK_STATE_3)
@@ -193,18 +197,18 @@ void x25_transmit_clear_request(struct x25_neigh *nb, unsigned int lci,
void x25_transmit_link(struct sk_buff *skb, struct x25_neigh *nb)
{
switch (nb->state) {
- case X25_LINK_STATE_0:
- skb_queue_tail(&nb->queue, skb);
- nb->state = X25_LINK_STATE_1;
- x25_establish_link(nb);
- break;
- case X25_LINK_STATE_1:
- case X25_LINK_STATE_2:
- skb_queue_tail(&nb->queue, skb);
- break;
- case X25_LINK_STATE_3:
- x25_send_frame(skb, nb);
- break;
+ case X25_LINK_STATE_0:
+ skb_queue_tail(&nb->queue, skb);
+ nb->state = X25_LINK_STATE_1;
+ x25_establish_link(nb);
+ break;
+ case X25_LINK_STATE_1:
+ case X25_LINK_STATE_2:
+ skb_queue_tail(&nb->queue, skb);
+ break;
+ case X25_LINK_STATE_3:
+ x25_send_frame(skb, nb);
+ break;
}
}
@@ -214,14 +218,14 @@ void x25_transmit_link(struct sk_buff *skb, struct x25_neigh *nb)
void x25_link_established(struct x25_neigh *nb)
{
switch (nb->state) {
- case X25_LINK_STATE_0:
- nb->state = X25_LINK_STATE_2;
- break;
- case X25_LINK_STATE_1:
- x25_transmit_restart_request(nb);
- nb->state = X25_LINK_STATE_2;
- x25_start_t20timer(nb);
- break;
+ case X25_LINK_STATE_0:
+ nb->state = X25_LINK_STATE_2;
+ break;
+ case X25_LINK_STATE_1:
+ x25_transmit_restart_request(nb);
+ nb->state = X25_LINK_STATE_2;
+ x25_start_t20timer(nb);
+ break;
}
}
@@ -396,8 +400,12 @@ void __exit x25_link_free(void)
write_lock_bh(&x25_neigh_list_lock);
list_for_each_safe(entry, tmp, &x25_neigh_list) {
+ struct net_device *dev;
+
nb = list_entry(entry, struct x25_neigh, node);
+ dev = nb->dev;
__x25_remove_neigh(nb);
+ dev_put(dev);
}
write_unlock_bh(&x25_neigh_list_lock);
}
diff --git a/net/x25/x25_out.c b/net/x25/x25_out.c
index d00649fb251..0144271d218 100644
--- a/net/x25/x25_out.c
+++ b/net/x25/x25_out.c
@@ -68,8 +68,11 @@ int x25_output(struct sock *sk, struct sk_buff *skb)
frontlen = skb_headroom(skb);
while (skb->len > 0) {
- if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len,
- noblock, &err)) == NULL){
+ release_sock(sk);
+ skbn = sock_alloc_send_skb(sk, frontlen + max_len,
+ noblock, &err);
+ lock_sock(sk);
+ if (!skbn) {
if (err == -EWOULDBLOCK && noblock){
kfree_skb(skb);
return sent;
diff --git a/net/x25/x25_proc.c b/net/x25/x25_proc.c
index 7ff37379232..0917f047f2c 100644
--- a/net/x25/x25_proc.c
+++ b/net/x25/x25_proc.c
@@ -20,6 +20,7 @@
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/export.h>
#include <net/net_namespace.h>
#include <net/sock.h>
#include <net/x25.h>
@@ -186,7 +187,6 @@ static int x25_seq_forward_open(struct inode *inode, struct file *file)
}
static const struct file_operations x25_seq_socket_fops = {
- .owner = THIS_MODULE,
.open = x25_seq_socket_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -194,7 +194,6 @@ static const struct file_operations x25_seq_socket_fops = {
};
static const struct file_operations x25_seq_route_fops = {
- .owner = THIS_MODULE,
.open = x25_seq_route_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -202,55 +201,38 @@ static const struct file_operations x25_seq_route_fops = {
};
static const struct file_operations x25_seq_forward_fops = {
- .owner = THIS_MODULE,
.open = x25_seq_forward_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
-static struct proc_dir_entry *x25_proc_dir;
-
int __init x25_proc_init(void)
{
- struct proc_dir_entry *p;
- int rc = -ENOMEM;
+ if (!proc_mkdir("x25", init_net.proc_net))
+ return -ENOMEM;
- x25_proc_dir = proc_mkdir("x25", init_net.proc_net);
- if (!x25_proc_dir)
+ if (!proc_create("x25/route", S_IRUGO, init_net.proc_net,
+ &x25_seq_route_fops))
goto out;
- p = proc_create("route", S_IRUGO, x25_proc_dir, &x25_seq_route_fops);
- if (!p)
- goto out_route;
-
- p = proc_create("socket", S_IRUGO, x25_proc_dir, &x25_seq_socket_fops);
- if (!p)
- goto out_socket;
+ if (!proc_create("x25/socket", S_IRUGO, init_net.proc_net,
+ &x25_seq_socket_fops))
+ goto out;
- p = proc_create("forward", S_IRUGO, x25_proc_dir,
- &x25_seq_forward_fops);
- if (!p)
- goto out_forward;
- rc = 0;
+ if (!proc_create("x25/forward", S_IRUGO, init_net.proc_net,
+ &x25_seq_forward_fops))
+ goto out;
+ return 0;
out:
- return rc;
-out_forward:
- remove_proc_entry("socket", x25_proc_dir);
-out_socket:
- remove_proc_entry("route", x25_proc_dir);
-out_route:
- remove_proc_entry("x25", init_net.proc_net);
- goto out;
+ remove_proc_subtree("x25", init_net.proc_net);
+ return -ENOMEM;
}
void __exit x25_proc_exit(void)
{
- remove_proc_entry("forward", x25_proc_dir);
- remove_proc_entry("route", x25_proc_dir);
- remove_proc_entry("socket", x25_proc_dir);
- remove_proc_entry("x25", init_net.proc_net);
+ remove_proc_subtree("x25", init_net.proc_net);
}
#else /* CONFIG_PROC_FS */
diff --git a/net/x25/x25_route.c b/net/x25/x25_route.c
index 97d77c532d8..277c8d2448d 100644
--- a/net/x25/x25_route.c
+++ b/net/x25/x25_route.c
@@ -66,7 +66,7 @@ out:
/**
* __x25_remove_route - remove route from x25_route_list
- * @rt - route to remove
+ * @rt: route to remove
*
* Remove route from x25_route_list. If it was there.
* Caller must hold x25_route_list_lock.
@@ -134,7 +134,7 @@ struct net_device *x25_dev_get(char *devname)
if (dev &&
(!(dev->flags & IFF_UP) || (dev->type != ARPHRD_X25
-#if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
+#if IS_ENABLED(CONFIG_LLC)
&& dev->type != ARPHRD_ETHER
#endif
))){
diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c
index dc20cf12f39..6b5af65f491 100644
--- a/net/x25/x25_subr.c
+++ b/net/x25/x25_subr.c
@@ -23,6 +23,8 @@
* restriction on response.
*/
+#define pr_fmt(fmt) "X25: " fmt
+
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -126,32 +128,30 @@ void x25_write_internal(struct sock *sk, int frametype)
* Adjust frame size.
*/
switch (frametype) {
- case X25_CALL_REQUEST:
- len += 1 + X25_ADDR_LEN + X25_MAX_FAC_LEN +
- X25_MAX_CUD_LEN;
- break;
- case X25_CALL_ACCEPTED: /* fast sel with no restr on resp */
- if(x25->facilities.reverse & 0x80) {
- len += 1 + X25_MAX_FAC_LEN + X25_MAX_CUD_LEN;
- } else {
- len += 1 + X25_MAX_FAC_LEN;
- }
- break;
- case X25_CLEAR_REQUEST:
- case X25_RESET_REQUEST:
- len += 2;
- break;
- case X25_RR:
- case X25_RNR:
- case X25_REJ:
- case X25_CLEAR_CONFIRMATION:
- case X25_INTERRUPT_CONFIRMATION:
- case X25_RESET_CONFIRMATION:
- break;
- default:
- printk(KERN_ERR "X.25: invalid frame type %02X\n",
- frametype);
- return;
+ case X25_CALL_REQUEST:
+ len += 1 + X25_ADDR_LEN + X25_MAX_FAC_LEN + X25_MAX_CUD_LEN;
+ break;
+ case X25_CALL_ACCEPTED: /* fast sel with no restr on resp */
+ if (x25->facilities.reverse & 0x80) {
+ len += 1 + X25_MAX_FAC_LEN + X25_MAX_CUD_LEN;
+ } else {
+ len += 1 + X25_MAX_FAC_LEN;
+ }
+ break;
+ case X25_CLEAR_REQUEST:
+ case X25_RESET_REQUEST:
+ len += 2;
+ break;
+ case X25_RR:
+ case X25_RNR:
+ case X25_REJ:
+ case X25_CLEAR_CONFIRMATION:
+ case X25_INTERRUPT_CONFIRMATION:
+ case X25_RESET_CONFIRMATION:
+ break;
+ default:
+ pr_err("invalid frame type %02X\n", frametype);
+ return;
}
if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
@@ -271,31 +271,39 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
int *d, int *m)
{
struct x25_sock *x25 = x25_sk(sk);
- unsigned char *frame = skb->data;
+ unsigned char *frame;
+
+ if (!pskb_may_pull(skb, X25_STD_MIN_LEN))
+ return X25_ILLEGAL;
+ frame = skb->data;
*ns = *nr = *q = *d = *m = 0;
switch (frame[2]) {
- case X25_CALL_REQUEST:
- case X25_CALL_ACCEPTED:
- case X25_CLEAR_REQUEST:
- case X25_CLEAR_CONFIRMATION:
- case X25_INTERRUPT:
- case X25_INTERRUPT_CONFIRMATION:
- case X25_RESET_REQUEST:
- case X25_RESET_CONFIRMATION:
- case X25_RESTART_REQUEST:
- case X25_RESTART_CONFIRMATION:
- case X25_REGISTRATION_REQUEST:
- case X25_REGISTRATION_CONFIRMATION:
- case X25_DIAGNOSTIC:
- return frame[2];
+ case X25_CALL_REQUEST:
+ case X25_CALL_ACCEPTED:
+ case X25_CLEAR_REQUEST:
+ case X25_CLEAR_CONFIRMATION:
+ case X25_INTERRUPT:
+ case X25_INTERRUPT_CONFIRMATION:
+ case X25_RESET_REQUEST:
+ case X25_RESET_CONFIRMATION:
+ case X25_RESTART_REQUEST:
+ case X25_RESTART_CONFIRMATION:
+ case X25_REGISTRATION_REQUEST:
+ case X25_REGISTRATION_CONFIRMATION:
+ case X25_DIAGNOSTIC:
+ return frame[2];
}
if (x25->neighbour->extended) {
if (frame[2] == X25_RR ||
frame[2] == X25_RNR ||
frame[2] == X25_REJ) {
+ if (!pskb_may_pull(skb, X25_EXT_MIN_LEN))
+ return X25_ILLEGAL;
+ frame = skb->data;
+
*nr = (frame[3] >> 1) & 0x7F;
return frame[2];
}
@@ -310,6 +318,10 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
if (x25->neighbour->extended) {
if ((frame[2] & 0x01) == X25_DATA) {
+ if (!pskb_may_pull(skb, X25_EXT_MIN_LEN))
+ return X25_ILLEGAL;
+ frame = skb->data;
+
*q = (frame[0] & X25_Q_BIT) == X25_Q_BIT;
*d = (frame[0] & X25_D_BIT) == X25_D_BIT;
*m = (frame[3] & X25_EXT_M_BIT) == X25_EXT_M_BIT;
@@ -328,7 +340,7 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
}
}
- printk(KERN_DEBUG "X.25: invalid PLP frame %02X %02X %02X\n",
+ pr_debug("invalid PLP frame %02X %02X %02X\n",
frame[0], frame[1], frame[2]);
return X25_ILLEGAL;