2020-11-16 07:35:14

by Martin Schiller

[permalink] [raw]
Subject: [PATCH 1/6] net/x25: add/remove x25_link_device by NETDEV_REGISTER/UNREGISTER

and also by NETDEV_POST_TYPE_CHANGE/NETDEV_PRE_TYPE_CHANGE.

This change is needed so that the x25_neigh struct for an interface is
already created when it shows up and is kept independantly if the
interface goes UP or DOWN.

This is used in the next commit, where x25 params of an neighbour will
get configurable through ioctls.

Signed-off-by: Martin Schiller <[email protected]>
---
include/net/x25.h | 2 ++
net/x25/af_x25.c | 19 +++++++++++++++++
net/x25/x25_link.c | 51 ++++++++++++++++++++++++++++++++++++++++------
3 files changed, 66 insertions(+), 6 deletions(-)

diff --git a/include/net/x25.h b/include/net/x25.h
index d7d6c2b4ffa7..af841c5ede28 100644
--- a/include/net/x25.h
+++ b/include/net/x25.h
@@ -231,6 +231,8 @@ int x25_backlog_rcv(struct sock *, struct sk_buff *);

/* x25_link.c */
void x25_link_control(struct sk_buff *, struct x25_neigh *, unsigned short);
+void x25_link_device_add(struct net_device *);
+void x25_link_device_remove(struct net_device *);
void x25_link_device_up(struct net_device *);
void x25_link_device_down(struct net_device *);
void x25_link_established(struct x25_neigh *);
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index a10487e7574c..d8e5ca251801 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -233,10 +233,20 @@ static int x25_device_event(struct notifier_block *this, unsigned long event,
#endif
) {
switch (event) {
+ case NETDEV_REGISTER:
+ pr_debug("X.25: got event NETDEV_REGISTER for device: %s\n", dev->name);
+ x25_link_device_add(dev);
+ break;
+ case NETDEV_POST_TYPE_CHANGE:
+ pr_debug("X.25: got event NETDEV_POST_TYPE_CHANGE for device: %s\n", dev->name);
+ x25_link_device_add(dev);
+ break;
case NETDEV_UP:
+ pr_debug("X.25: got event NETDEV_UP for device: %s\n", dev->name);
x25_link_device_up(dev);
break;
case NETDEV_GOING_DOWN:
+ pr_debug("X.25: got event NETDEV_GOING_DOWN for device: %s\n", dev->name);
nb = x25_get_neigh(dev);
if (nb) {
x25_terminate_link(nb);
@@ -244,10 +254,19 @@ static int x25_device_event(struct notifier_block *this, unsigned long event,
}
break;
case NETDEV_DOWN:
+ pr_debug("X.25: got event NETDEV_DOWN for device: %s\n", dev->name);
x25_kill_by_device(dev);
x25_route_device_down(dev);
x25_link_device_down(dev);
break;
+ case NETDEV_PRE_TYPE_CHANGE:
+ pr_debug("X.25: got event NETDEV_PRE_TYPE_CHANGE for device: %s\n", dev->name);
+ x25_link_device_remove(dev);
+ break;
+ case NETDEV_UNREGISTER:
+ pr_debug("X.25: got event NETDEV_UNREGISTER for device: %s\n", dev->name);
+ x25_link_device_remove(dev);
+ break;
}
}

diff --git a/net/x25/x25_link.c b/net/x25/x25_link.c
index fdae054b7dc1..22055ee40056 100644
--- a/net/x25/x25_link.c
+++ b/net/x25/x25_link.c
@@ -239,9 +239,19 @@ void x25_link_terminated(struct x25_neigh *nb)
/*
* Add a new device.
*/
-void x25_link_device_up(struct net_device *dev)
+void x25_link_device_add(struct net_device *dev)
{
- struct x25_neigh *nb = kmalloc(sizeof(*nb), GFP_ATOMIC);
+ struct x25_neigh *nb = x25_get_neigh(dev);
+
+ /*
+ * Check, if we already have a neighbour for this device
+ */
+ if (nb) {
+ x25_neigh_put(nb);
+ return;
+ }
+
+ nb = kmalloc(sizeof(*nb), GFP_ATOMIC);

if (!nb)
return;
@@ -268,6 +278,22 @@ void x25_link_device_up(struct net_device *dev)
write_unlock_bh(&x25_neigh_list_lock);
}

+/*
+ * A device is coming up
+ */
+void x25_link_device_up(struct net_device *dev)
+{
+ struct x25_neigh *nb = x25_get_neigh(dev);
+
+ if (!nb)
+ return;
+
+ nb->state = X25_LINK_STATE_1;
+ x25_establish_link(nb);
+
+ x25_neigh_put(nb);
+}
+
/**
* __x25_remove_neigh - remove neighbour from x25_neigh_list
* @nb: - neigh to remove
@@ -277,9 +303,6 @@ void x25_link_device_up(struct net_device *dev)
*/
static void __x25_remove_neigh(struct x25_neigh *nb)
{
- skb_queue_purge(&nb->queue);
- x25_stop_t20timer(nb);
-
if (nb->node.next) {
list_del(&nb->node);
x25_neigh_put(nb);
@@ -289,7 +312,7 @@ static void __x25_remove_neigh(struct x25_neigh *nb)
/*
* A device has been removed, remove its links.
*/
-void x25_link_device_down(struct net_device *dev)
+void x25_link_device_remove(struct net_device *dev)
{
struct x25_neigh *nb;
struct list_head *entry, *tmp;
@@ -308,6 +331,22 @@ void x25_link_device_down(struct net_device *dev)
write_unlock_bh(&x25_neigh_list_lock);
}

+/*
+ * A device is going down
+ */
+void x25_link_device_down(struct net_device *dev)
+{
+ struct x25_neigh *nb = x25_get_neigh(dev);
+
+ if (!nb)
+ return;
+
+ skb_queue_purge(&nb->queue);
+ x25_stop_t20timer(nb);
+
+ x25_neigh_put(nb);
+}
+
/*
* Given a device, return the neighbour address.
*/
--
2.20.1


2020-11-16 07:35:28

by Martin Schiller

[permalink] [raw]
Subject: [PATCH 2/6] net/x25: make neighbour params configurable

Extended struct x25_neigh and x25_subscrip_struct to configure following
params through SIOCX25SSUBSCRIP:
o mode (DTE/DCE)
o number of channels
o facilities (packet size, window size)
o timer T20

Based on this configuration options the follwing changes/extensions
where made:
o DTE/DCE handling to select the next lc (DCE=from bottom / DTE=from
top)
o DTE/DCE handling to set correct clear/reset/restart cause
o take default facilities from neighbour settings

Signed-off-by: Martin Schiller <[email protected]>
---
include/net/x25.h | 7 ++-
include/uapi/linux/x25.h | 54 ++++++++--------
net/x25/af_x25.c | 132 ++++++++++++++++++++++++++++++++-------
net/x25/x25_facilities.c | 6 +-
net/x25/x25_link.c | 104 +++++++++++++++++++++++++-----
net/x25/x25_subr.c | 22 ++++++-
6 files changed, 255 insertions(+), 70 deletions(-)

diff --git a/include/net/x25.h b/include/net/x25.h
index af841c5ede28..6e8600456d39 100644
--- a/include/net/x25.h
+++ b/include/net/x25.h
@@ -140,6 +140,9 @@ struct x25_neigh {
struct net_device *dev;
unsigned int state;
unsigned int extended;
+ unsigned int dce;
+ unsigned int lc;
+ struct x25_facilities facilities;
struct sk_buff_head queue;
unsigned long t20;
struct timer_list t20timer;
@@ -164,6 +167,7 @@ struct x25_sock {
struct timer_list timer;
struct x25_causediag causediag;
struct x25_facilities facilities;
+ unsigned int socket_defined_facilities; /* set, if facilities changed by SIOCX25SFACILITIES */
struct x25_dte_facilities dte_facilities;
struct x25_calluserdata calluserdata;
unsigned long vc_facil_mask; /* inc_call facilities mask */
@@ -215,7 +219,8 @@ int x25_create_facilities(unsigned char *, struct x25_facilities *,
struct x25_dte_facilities *, unsigned long);
int x25_negotiate_facilities(struct sk_buff *, struct sock *,
struct x25_facilities *,
- struct x25_dte_facilities *);
+ struct x25_dte_facilities *,
+ struct x25_neigh *);
void x25_limit_facilities(struct x25_facilities *, struct x25_neigh *);

/* x25_forward.c */
diff --git a/include/uapi/linux/x25.h b/include/uapi/linux/x25.h
index 034b7dc5593a..963848e94880 100644
--- a/include/uapi/linux/x25.h
+++ b/include/uapi/linux/x25.h
@@ -63,31 +63,6 @@ struct sockaddr_x25 {
struct x25_address sx25_addr; /* X.121 Address */
};

-/*
- * DTE/DCE subscription options.
- *
- * As this is missing lots of options, user should expect major
- * changes of this structure in 2.5.x which might break compatibilty.
- * The somewhat ugly dimension 200-sizeof() is needed to maintain
- * backward compatibility.
- */
-struct x25_subscrip_struct {
- char device[200-sizeof(unsigned long)];
- unsigned long global_facil_mask; /* 0 to disable negotiation */
- unsigned int extended;
-};
-
-/* values for above global_facil_mask */
-
-#define X25_MASK_REVERSE 0x01
-#define X25_MASK_THROUGHPUT 0x02
-#define X25_MASK_PACKET_SIZE 0x04
-#define X25_MASK_WINDOW_SIZE 0x08
-
-#define X25_MASK_CALLING_AE 0x10
-#define X25_MASK_CALLED_AE 0x20
-
-
/*
* Routing table control structure.
*/
@@ -127,6 +102,35 @@ struct x25_dte_facilities {
__u8 called_ae[20];
};

+/*
+ * DTE/DCE subscription options.
+ *
+ * As this is missing lots of options, user should expect major
+ * changes of this structure in 2.5.x which might break compatibilty.
+ * The somewhat ugly dimension 200-sizeof() is needed to maintain
+ * backward compatibility.
+ */
+struct x25_subscrip_struct {
+ char device[200-((2 * sizeof(unsigned long)) + sizeof(struct x25_facilities) + (2 * sizeof(unsigned int)))];
+ unsigned int dce;
+ unsigned int lc;
+ struct x25_facilities facilities;
+ unsigned long t20;
+ unsigned long global_facil_mask; /* 0 to disable negotiation */
+ unsigned int extended;
+};
+
+/* values for above global_facil_mask */
+
+#define X25_MASK_REVERSE 0x01
+#define X25_MASK_THROUGHPUT 0x02
+#define X25_MASK_PACKET_SIZE 0x04
+#define X25_MASK_WINDOW_SIZE 0x08
+
+#define X25_MASK_CALLING_AE 0x10
+#define X25_MASK_CALLED_AE 0x20
+
+
/*
* Call User Data structure.
*/
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index d8e5ca251801..439ae65ab7a8 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -72,8 +72,19 @@ static const struct proto_ops x25_proto_ops;
static const struct x25_address null_x25_address = {" "};

#ifdef CONFIG_COMPAT
+struct compat_x25_facilities {
+ compat_uint_t winsize_in, winsize_out;
+ compat_uint_t pacsize_in, pacsize_out;
+ compat_uint_t throughput;
+ compat_uint_t reverse;
+};
+
struct compat_x25_subscrip_struct {
- char device[200-sizeof(compat_ulong_t)];
+ char device[200-((2 * sizeof(compat_ulong_t)) + sizeof(struct compat_x25_facilities) + (2 * sizeof(compat_uint_t)))];
+ compat_uint_t dce;
+ compat_uint_t lc;
+ struct compat_x25_facilities facilities;
+ compat_ulong_t t20;
compat_ulong_t global_facil_mask;
compat_uint_t extended;
};
@@ -366,13 +377,26 @@ static unsigned int x25_new_lci(struct x25_neigh *nb)
unsigned int lci = 1;
struct sock *sk;

- while ((sk = x25_find_socket(lci, nb)) != NULL) {
- sock_put(sk);
- if (++lci == 4096) {
- lci = 0;
- break;
+ if (nb->dce) {
+ while ((sk = x25_find_socket(lci, nb)) != NULL) {
+ sock_put(sk);
+ if (++lci > nb->lc) {
+ lci = 0;
+ break;
+ }
+ cond_resched();
+ }
+ } else {
+ lci = nb->lc;
+
+ while ((sk = x25_find_socket(lci, nb)) != NULL) {
+ sock_put(sk);
+ if (--lci == 0) {
+ lci = 0;
+ break;
+ }
+ cond_resched();
}
- cond_resched();
}

return lci;
@@ -806,6 +830,10 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr,
if (!x25->neighbour)
goto out_put_route;

+ if (!x25->socket_defined_facilities)
+ memcpy(&x25->facilities, &x25->neighbour->facilities,
+ sizeof(struct x25_facilities));
+
x25_limit_facilities(&x25->facilities, x25->neighbour);

x25->lci = x25_new_lci(x25->neighbour);
@@ -1039,7 +1067,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
/*
* Try to reach a compromise on the requested facilities.
*/
- len = x25_negotiate_facilities(skb, sk, &facilities, &dte_facilities);
+ len = x25_negotiate_facilities(skb, sk, &facilities, &dte_facilities, nb);
if (len == -1)
goto out_sock_put;

@@ -1454,10 +1482,15 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
rc = x25_subscr_ioctl(cmd, argp);
break;
case SIOCX25GFACILITIES: {
+ rc = -EINVAL;
lock_sock(sk);
+ if (sk->sk_state != TCP_ESTABLISHED &&
+ !x25->socket_defined_facilities)
+ goto out_gfac_release;
rc = copy_to_user(argp, &x25->facilities,
sizeof(x25->facilities))
? -EFAULT : 0;
+out_gfac_release:
release_sock(sk);
break;
}
@@ -1471,16 +1504,16 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
lock_sock(sk);
if (sk->sk_state != TCP_LISTEN &&
sk->sk_state != TCP_CLOSE)
- goto out_fac_release;
+ goto out_sfac_release;
if (facilities.pacsize_in < X25_PS16 ||
facilities.pacsize_in > X25_PS4096)
- goto out_fac_release;
+ goto out_sfac_release;
if (facilities.pacsize_out < X25_PS16 ||
facilities.pacsize_out > X25_PS4096)
- goto out_fac_release;
+ goto out_sfac_release;
if (facilities.winsize_in < 1 ||
facilities.winsize_in > 127)
- goto out_fac_release;
+ goto out_sfac_release;
if (facilities.throughput) {
int out = facilities.throughput & 0xf0;
int in = facilities.throughput & 0x0f;
@@ -1488,19 +1521,20 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
facilities.throughput |=
X25_DEFAULT_THROUGHPUT << 4;
else if (out < 0x30 || out > 0xD0)
- goto out_fac_release;
+ goto out_sfac_release;
if (!in)
facilities.throughput |=
X25_DEFAULT_THROUGHPUT;
else if (in < 0x03 || in > 0x0D)
- goto out_fac_release;
+ goto out_sfac_release;
}
if (facilities.reverse &&
(facilities.reverse & 0x81) != 0x81)
- goto out_fac_release;
+ goto out_sfac_release;
x25->facilities = facilities;
+ x25->socket_defined_facilities = 1;
rc = 0;
-out_fac_release:
+out_sfac_release:
release_sock(sk);
break;
}
@@ -1652,6 +1686,9 @@ static int compat_x25_subscr_ioctl(unsigned int cmd,
struct net_device *dev;
int rc = -EINVAL;

+ if (cmd != SIOCX25GSUBSCRIP && cmd != SIOCX25SSUBSCRIP)
+ goto out;
+
rc = -EFAULT;
if (copy_from_user(&x25_subscr, x25_subscr32, sizeof(*x25_subscr32)))
goto out;
@@ -1665,28 +1702,75 @@ static int compat_x25_subscr_ioctl(unsigned int cmd,
if (nb == NULL)
goto out_dev_put;

- dev_put(dev);
-
if (cmd == SIOCX25GSUBSCRIP) {
read_lock_bh(&x25_neigh_list_lock);
x25_subscr.extended = nb->extended;
+ x25_subscr.dce = nb->dce;
+ x25_subscr.lc = nb->lc;
+ x25_subscr.facilities = nb->facilities;
+ x25_subscr.t20 = nb->t20;
x25_subscr.global_facil_mask = nb->global_facil_mask;
read_unlock_bh(&x25_neigh_list_lock);
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;
- write_lock_bh(&x25_neigh_list_lock);
- nb->extended = x25_subscr.extended;
- nb->global_facil_mask = x25_subscr.global_facil_mask;
- write_unlock_bh(&x25_neigh_list_lock);
+
+ if (dev->flags & IFF_UP)
+ return -EBUSY;
+
+ if (x25_subscr.extended != 0 && x25_subscr.extended != 1)
+ goto out_dev_and_neigh_put;
+ if (x25_subscr.dce != 0 && x25_subscr.dce != 1)
+ goto out_dev_and_neigh_put;
+ if (x25_subscr.lc < 1 || x25_subscr.lc > 4095)
+ goto out_dev_and_neigh_put;
+ if (x25_subscr.facilities.pacsize_in < X25_PS16 ||
+ x25_subscr.facilities.pacsize_in > X25_PS4096)
+ goto out_dev_and_neigh_put;
+ if (x25_subscr.facilities.pacsize_out < X25_PS16 ||
+ x25_subscr.facilities.pacsize_out > X25_PS4096)
+ goto out_dev_and_neigh_put;
+ if (x25_subscr.facilities.winsize_in < 1 ||
+ x25_subscr.facilities.winsize_in > 127)
+ goto out_dev_and_neigh_put;
+ if (x25_subscr.facilities.throughput) {
+ int out = x25_subscr.facilities.throughput & 0xf0;
+ int in = x25_subscr.facilities.throughput & 0x0f;
+ if (!out)
+ x25_subscr.facilities.throughput |=
+ X25_DEFAULT_THROUGHPUT << 4;
+ else if (out < 0x30 || out > 0xD0)
+ goto out_dev_and_neigh_put;
+ if (!in)
+ x25_subscr.facilities.throughput |=
+ X25_DEFAULT_THROUGHPUT;
+ else if (in < 0x03 || in > 0x0D)
+ goto out_dev_and_neigh_put;
}
+ if (x25_subscr.facilities.reverse &&
+ (x25_subscr.facilities.reverse & 0x81) != 0x81)
+ goto out_dev_and_neigh_put;
+ if (x25_subscr.t20 < 1 * HZ || x25_subscr.t20 > 300 * HZ)
+ goto out_dev_and_neigh_put;
+
+ rc = 0;
+ write_lock_bh(&x25_neigh_list_lock);
+ nb->extended = x25_subscr.extended;
+ nb->dce = x25_subscr.dce;
+ nb->lc = x25_subscr.lc;
+ nb->facilities = x25_subscr.facilities;
+ nb->t20 = x25_subscr.t20;
+ nb->global_facil_mask = x25_subscr.global_facil_mask;
+ write_unlock_bh(&x25_neigh_list_lock);
}
+ dev_put(dev);
+
x25_neigh_put(nb);
out:
return rc;
+out_dev_and_neigh_put:
+ x25_neigh_put(nb);
out_dev_put:
dev_put(dev);
goto out;
diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c
index 8e1a49b0c0dc..e6c9f9376206 100644
--- a/net/x25/x25_facilities.c
+++ b/net/x25/x25_facilities.c
@@ -263,13 +263,17 @@ int x25_create_facilities(unsigned char *buffer,
* The only real problem is with reverse charging.
*/
int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk,
- struct x25_facilities *new, struct x25_dte_facilities *dte)
+ struct x25_facilities *new, struct x25_dte_facilities *dte,
+ struct x25_neigh *nb)
{
struct x25_sock *x25 = x25_sk(sk);
struct x25_facilities *ours = &x25->facilities;
struct x25_facilities theirs;
int len;

+ if (!x25->socket_defined_facilities)
+ ours = &nb->facilities;
+
memset(&theirs, 0, sizeof(theirs));
memcpy(new, ours, sizeof(*new));
memset(dte, 0, sizeof(*dte));
diff --git a/net/x25/x25_link.c b/net/x25/x25_link.c
index 22055ee40056..fabac6331a59 100644
--- a/net/x25/x25_link.c
+++ b/net/x25/x25_link.c
@@ -125,8 +125,16 @@ static void x25_transmit_restart_request(struct x25_neigh *nb)
*dptr++ = nb->extended ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
*dptr++ = 0x00;
*dptr++ = X25_RESTART_REQUEST;
- *dptr++ = 0x00;
- *dptr++ = 0;
+
+ *dptr = 0x00; /* cause */
+
+ /* set bit 8, if DTE and cause != 0x00 */
+ if (!nb->dce && *dptr != 0x00)
+ *dptr |= (unsigned char) 0x80;
+
+ dptr++;
+
+ *dptr++ = 0x00; /* diagnostic */

skb->sk = NULL;

@@ -181,8 +189,16 @@ void x25_transmit_clear_request(struct x25_neigh *nb, unsigned int lci,
X25_GFI_STDSEQ);
*dptr++ = (lci >> 0) & 0xFF;
*dptr++ = X25_CLEAR_REQUEST;
- *dptr++ = cause;
- *dptr++ = 0x00;
+
+ *dptr = cause; /* cause */
+
+ /* set bit 8, if DTE and cause != 0x00 */
+ if (!nb->dce && *dptr != 0x00)
+ *dptr |= (unsigned char) 0x80;
+
+ dptr++;
+
+ *dptr++ = 0x00; /* diagnostic */

skb->sk = NULL;

@@ -260,9 +276,19 @@ void x25_link_device_add(struct net_device *dev)
timer_setup(&nb->t20timer, x25_t20timer_expiry, 0);

dev_hold(dev);
- nb->dev = dev;
- nb->state = X25_LINK_STATE_0;
- nb->extended = 0;
+ nb->dev = dev;
+ nb->state = X25_LINK_STATE_0;
+ nb->extended = 0;
+ nb->dce = 0;
+ nb->lc = 10;
+ nb->facilities.winsize_in = X25_DEFAULT_WINDOW_SIZE;
+ nb->facilities.winsize_out = X25_DEFAULT_WINDOW_SIZE;
+ nb->facilities.pacsize_in = X25_DEFAULT_PACKET_SIZE;
+ nb->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE;
+ nb->facilities.throughput = 0; /* by default don't negotiate
+ throughput */
+ nb->facilities.reverse = X25_DEFAULT_REVERSE;
+ nb->t20 = sysctl_x25_restart_request_timeout;
/*
* Enables negotiation
*/
@@ -270,7 +296,6 @@ void x25_link_device_add(struct net_device *dev)
X25_MASK_THROUGHPUT |
X25_MASK_PACKET_SIZE |
X25_MASK_WINDOW_SIZE;
- nb->t20 = sysctl_x25_restart_request_timeout;
refcount_set(&nb->refcnt, 1);

write_lock_bh(&x25_neigh_list_lock);
@@ -395,28 +420,75 @@ int x25_subscr_ioctl(unsigned int cmd, void __user *arg)
if ((nb = x25_get_neigh(dev)) == NULL)
goto out_dev_put;

- dev_put(dev);
-
if (cmd == SIOCX25GSUBSCRIP) {
read_lock_bh(&x25_neigh_list_lock);
x25_subscr.extended = nb->extended;
+ x25_subscr.dce = nb->dce;
+ x25_subscr.lc = nb->lc;
+ x25_subscr.facilities = nb->facilities;
+ x25_subscr.t20 = nb->t20;
x25_subscr.global_facil_mask = nb->global_facil_mask;
read_unlock_bh(&x25_neigh_list_lock);
rc = copy_to_user(arg, &x25_subscr,
sizeof(x25_subscr)) ? -EFAULT : 0;
} else {
rc = -EINVAL;
- if (!(x25_subscr.extended && x25_subscr.extended != 1)) {
- rc = 0;
- write_lock_bh(&x25_neigh_list_lock);
- nb->extended = x25_subscr.extended;
- nb->global_facil_mask = x25_subscr.global_facil_mask;
- write_unlock_bh(&x25_neigh_list_lock);
+
+ if (dev->flags & IFF_UP)
+ return -EBUSY;
+
+ if (x25_subscr.extended != 0 && x25_subscr.extended != 1)
+ goto out_dev_and_neigh_put;
+ if (x25_subscr.dce != 0 && x25_subscr.dce != 1)
+ goto out_dev_and_neigh_put;
+ if (x25_subscr.lc < 1 || x25_subscr.lc > 4095)
+ goto out_dev_and_neigh_put;
+ if (x25_subscr.facilities.pacsize_in < X25_PS16 ||
+ x25_subscr.facilities.pacsize_in > X25_PS4096)
+ goto out_dev_and_neigh_put;
+ if (x25_subscr.facilities.pacsize_out < X25_PS16 ||
+ x25_subscr.facilities.pacsize_out > X25_PS4096)
+ goto out_dev_and_neigh_put;
+ if (x25_subscr.facilities.winsize_in < 1 ||
+ x25_subscr.facilities.winsize_in > 127)
+ goto out_dev_and_neigh_put;
+ if (x25_subscr.facilities.throughput) {
+ int out = x25_subscr.facilities.throughput & 0xf0;
+ int in = x25_subscr.facilities.throughput & 0x0f;
+ if (!out)
+ x25_subscr.facilities.throughput |=
+ X25_DEFAULT_THROUGHPUT << 4;
+ else if (out < 0x30 || out > 0xD0)
+ goto out_dev_and_neigh_put;
+ if (!in)
+ x25_subscr.facilities.throughput |=
+ X25_DEFAULT_THROUGHPUT;
+ else if (in < 0x03 || in > 0x0D)
+ goto out_dev_and_neigh_put;
}
+ if (x25_subscr.facilities.reverse &&
+ (x25_subscr.facilities.reverse & 0x81) != 0x81)
+ goto out_dev_and_neigh_put;
+ if (x25_subscr.t20 < 1 * HZ || x25_subscr.t20 > 300 * HZ)
+ goto out_dev_and_neigh_put;
+
+ rc = 0;
+ write_lock_bh(&x25_neigh_list_lock);
+ nb->extended = x25_subscr.extended;
+ nb->dce = x25_subscr.dce;
+ nb->lc = x25_subscr.lc;
+ nb->facilities = x25_subscr.facilities;
+ nb->t20 = x25_subscr.t20;
+ nb->global_facil_mask = x25_subscr.global_facil_mask;
+ write_unlock_bh(&x25_neigh_list_lock);
}
+ dev_put(dev);
+
x25_neigh_put(nb);
out:
return rc;
+out_dev_and_neigh_put:
+ x25_neigh_put(nb);
out_dev_put:
dev_put(dev);
goto out;
diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c
index 0285aaa1e93c..b1bbabfbe26f 100644
--- a/net/x25/x25_subr.c
+++ b/net/x25/x25_subr.c
@@ -218,15 +218,31 @@ void x25_write_internal(struct sock *sk, int frametype)
case X25_CLEAR_REQUEST:
dptr = skb_put(skb, 3);
*dptr++ = frametype;
- *dptr++ = x25->causediag.cause;
+
+ *dptr = x25->causediag.cause;
+
+ /* set bit 8, if DTE and cause != 0x00 */
+ if (!x25->neighbour->dce && *dptr != 0x00)
+ *dptr |= (unsigned char) 0x80;
+
+ dptr++;
+
*dptr++ = x25->causediag.diagnostic;
break;

case X25_RESET_REQUEST:
dptr = skb_put(skb, 3);
*dptr++ = frametype;
- *dptr++ = 0x00; /* XXX */
- *dptr++ = 0x00; /* XXX */
+
+ *dptr = 0x00; /* cause */
+
+ /* set bit 8, if DTE and cause != 0x00 */
+ if (!x25->neighbour->dce && *dptr != 0x00)
+ *dptr |= (unsigned char) 0x80;
+
+ dptr++;
+
+ *dptr++ = 0x00; /* diagnostic */
break;

case X25_RR:
--
2.20.1

2020-11-16 07:36:38

by Martin Schiller

[permalink] [raw]
Subject: [PATCH 5/6] net/lapb: support netdev events

This makes it possible to handle carrier loss and detection.
In case of Carrier Loss, layer 2 is terminated
In case of Carrier Detection, we start timer t1 on a DCE interface,
and on a DTE interface we change to state LAPB_STATE_1 and start
sending SABM(E).

Signed-off-by: Martin Schiller <[email protected]>
---
net/lapb/lapb_iface.c | 74 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 74 insertions(+)

diff --git a/net/lapb/lapb_iface.c b/net/lapb/lapb_iface.c
index 3c03f6512c5f..6a109c8c286f 100644
--- a/net/lapb/lapb_iface.c
+++ b/net/lapb/lapb_iface.c
@@ -418,14 +418,88 @@ int lapb_data_transmit(struct lapb_cb *lapb, struct sk_buff *skb)
return used;
}

+/*
+ * Handle device status changes.
+ */
+static int lapb_device_event(struct notifier_block *this, unsigned long event,
+ void *ptr)
+{
+ struct net_device *dev = ptr;
+ struct lapb_cb *lapb;
+
+ if (!net_eq(dev_net(dev), &init_net))
+ return NOTIFY_DONE;
+
+ if (dev->type == ARPHRD_X25) {
+ switch (event) {
+ case NETDEV_REGISTER:
+ lapb_dbg(0, "(%p): got event NETDEV_REGISTER for device: %s\n", dev, dev->name);
+ break;
+ case NETDEV_POST_TYPE_CHANGE:
+ lapb_dbg(0, "(%p): got event NETDEV_POST_TYPE_CHANGE for device: %s\n", dev, dev->name);
+ break;
+ case NETDEV_UP:
+ lapb_dbg(0, "(%p): got event NETDEV_UP for device: %s\n", dev, dev->name);
+ break;
+ case NETDEV_GOING_DOWN:
+ lapb_dbg(0, "(%p): got event NETDEV_GOING_DOWN for device: %s\n", dev, dev->name);
+ break;
+ case NETDEV_DOWN:
+ lapb_dbg(0, "(%p): got event NETDEV_DOWN for device: %s\n", dev, dev->name);
+ break;
+ case NETDEV_PRE_TYPE_CHANGE:
+ lapb_dbg(0, "(%p): got event NETDEV_PRE_TYPE_CHANGE for device: %s\n", dev, dev->name);
+ break;
+ case NETDEV_UNREGISTER:
+ lapb_dbg(0, "(%p): got event NETDEV_UNREGISTER for device: %s\n", dev, dev->name);
+ break;
+ case NETDEV_CHANGE:
+ lapb_dbg(0, "(%p): got event NETDEV_CHANGE for device: %s\n", dev, dev->name);
+ lapb = lapb_devtostruct(dev);
+ if (lapb) {
+ if (!netif_carrier_ok(dev)) {
+ lapb_dbg(0, "(%p): Carrier lost -> Entering LAPB_STATE_0: %s\n", dev, dev->name);
+ lapb_disconnect_indication(lapb, LAPB_OK);
+ lapb_clear_queues(lapb);
+ lapb->state = LAPB_STATE_0;
+ lapb->n2count = 0;
+ lapb_stop_t1timer(lapb);
+ lapb_stop_t2timer(lapb);
+ } else {
+ lapb_dbg(0, "(%p): Carrier detected: %s\n", dev, dev->name);
+ if (lapb->mode & LAPB_DCE) {
+ lapb_start_t1timer(lapb);
+ } else {
+ if (lapb->state == LAPB_STATE_0) {
+ lapb->state = LAPB_STATE_1;
+ lapb_establish_data_link(lapb);
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block lapb_dev_notifier = {
+ .notifier_call = lapb_device_event,
+};
+
static int __init lapb_init(void)
{
+ register_netdevice_notifier(&lapb_dev_notifier);
+
return 0;
}

static void __exit lapb_exit(void)
{
WARN_ON(!list_empty(&lapb_list));
+
+ unregister_netdevice_notifier(&lapb_dev_notifier);
}

MODULE_AUTHOR("Jonathan Naylor <[email protected]>");
--
2.20.1

2020-11-16 07:36:53

by Martin Schiller

[permalink] [raw]
Subject: [PATCH 6/6] net/lapb: fix t1 timer handling

fix t1 timer handling in LAPB_STATE_0:
o DTE interface changes immediately to LAPB_STATE_1 and start sending
SABM(E).
o DCE interface sends N2-times DM and changes to LAPB_STATE_1
afterwards if there is no response in the meantime.

Signed-off-by: Martin Schiller <[email protected]>
---
net/lapb/lapb_timer.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/net/lapb/lapb_timer.c b/net/lapb/lapb_timer.c
index 8f5b17001a07..d1f80d67892f 100644
--- a/net/lapb/lapb_timer.c
+++ b/net/lapb/lapb_timer.c
@@ -85,11 +85,16 @@ static void lapb_t1timer_expiry(struct timer_list *t)
switch (lapb->state) {

/*
- * If we are a DCE, keep going DM .. DM .. DM
+ * If we are a DCE, send DM up to N2 times, then switch to STATE_1 and send SABM(E)
*/
case LAPB_STATE_0:
- if (lapb->mode & LAPB_DCE)
+ if (lapb->mode & LAPB_DCE && lapb->n2count != lapb->n2) {
+ lapb->n2count++;
lapb_send_control(lapb, LAPB_DM, LAPB_POLLOFF, LAPB_RESPONSE);
+ } else {
+ lapb->state = LAPB_STATE_1;
+ lapb_establish_data_link(lapb);
+ }
break;

/*
--
2.20.1

2020-11-16 07:37:15

by Martin Schiller

[permalink] [raw]
Subject: [PATCH 3/6] net/x25: replace x25_kill_by_device with x25_kill_by_neigh

Remove unnecessary function x25_kill_by_device.

Signed-off-by: Martin Schiller <[email protected]>
---
net/x25/af_x25.c | 22 +++++-----------------
1 file changed, 5 insertions(+), 17 deletions(-)

diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index 439ae65ab7a8..d98d1145500e 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -210,22 +210,6 @@ static void x25_remove_socket(struct sock *sk)
write_unlock_bh(&x25_list_lock);
}

-/*
- * 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.
*/
@@ -266,7 +250,11 @@ static int x25_device_event(struct notifier_block *this, unsigned long event,
break;
case NETDEV_DOWN:
pr_debug("X.25: got event NETDEV_DOWN for device: %s\n", dev->name);
- x25_kill_by_device(dev);
+ nb = x25_get_neigh(dev);
+ if (nb) {
+ x25_kill_by_neigh(nb);
+ x25_neigh_put(nb);
+ }
x25_route_device_down(dev);
x25_link_device_down(dev);
break;
--
2.20.1

2020-11-16 07:38:05

by Martin Schiller

[permalink] [raw]
Subject: [PATCH 4/6] net/x25: support NETDEV_CHANGE notifier

This makes it possible to handle carrier lost and detection.
In case of carrier lost, we shutdown layer 3 and flush all sessions.

Signed-off-by: Martin Schiller <[email protected]>
---
net/x25/af_x25.c | 11 +++++++++++
1 file changed, 11 insertions(+)

diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index d98d1145500e..d61a154b94e4 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -266,6 +266,17 @@ static int x25_device_event(struct notifier_block *this, unsigned long event,
pr_debug("X.25: got event NETDEV_UNREGISTER for device: %s\n", dev->name);
x25_link_device_remove(dev);
break;
+ case NETDEV_CHANGE:
+ pr_debug("X.25: got event NETDEV_CHANGE for device: %s\n", dev->name);
+ if (!netif_carrier_ok(dev)) {
+ pr_debug("X.25: Carrier lost -> set link state down: %s\n", dev->name);
+ nb = x25_get_neigh(dev);
+ if (nb) {
+ x25_link_terminated(nb);
+ x25_neigh_put(nb);
+ }
+ }
+ break;
}
}

--
2.20.1

2020-11-16 08:49:28

by Xie He

[permalink] [raw]
Subject: Re: [PATCH 1/6] net/x25: add/remove x25_link_device by NETDEV_REGISTER/UNREGISTER

Hi Martin,

Thanks for the series. To get the series applied faster, could you
address the warnings and failures shown on this page?
https://patchwork.kernel.org/project/netdevbpf/list/?submitter=174539
Thanks!

To let the netdev robot know which tree this series should be applied,
we can use [PATCH net-next 1/6] as the subject prefix.

2020-11-16 09:03:04

by Martin Schiller

[permalink] [raw]
Subject: Re: [PATCH 1/6] net/x25: add/remove x25_link_device by NETDEV_REGISTER/UNREGISTER

On 2020-11-16 09:45, Xie He wrote:
> Hi Martin,
>
> Thanks for the series. To get the series applied faster, could you
> address the warnings and failures shown on this page?
> https://patchwork.kernel.org/project/netdevbpf/list/?submitter=174539
> Thanks!
>
> To let the netdev robot know which tree this series should be applied,
> we can use [PATCH net-next 1/6] as the subject prefix.

Hi Xie!

Thanks. I will have a look at this.

2020-11-16 20:12:19

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 2/6] net/x25: make neighbour params configurable

Hi Martin,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on net-next/master]
[also build test ERROR on net/master linus/master sparc-next/master v5.10-rc4 next-20201116]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/Martin-Schiller/net-x25-add-remove-x25_link_device-by-NETDEV_REGISTER-UNREGISTER/20201116-153459
base: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git 0064c5c1b3bf2a695c772c90e8dea38426a870ff
config: x86_64-randconfig-a011-20201116 (attached as .config)
compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project c044709b8fbea2a9a375e4173a6bd735f6866c0c)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install x86_64 cross compiling tool for clang build
# apt-get install binutils-x86-64-linux-gnu
# https://github.com/0day-ci/linux/commit/2d44533245f7e8388db93c53c26703ac52650e57
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Martin-Schiller/net-x25-add-remove-x25_link_device-by-NETDEV_REGISTER-UNREGISTER/20201116-153459
git checkout 2d44533245f7e8388db93c53c26703ac52650e57
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All errors (new ones prefixed by >>):

>> net/x25/af_x25.c:1709:30: error: assigning to 'struct compat_x25_facilities' from incompatible type 'struct x25_facilities'
x25_subscr.facilities = nb->facilities;
^ ~~~~~~~~~~~~~~
>> net/x25/af_x25.c:1761:24: error: assigning to 'struct x25_facilities' from incompatible type 'struct compat_x25_facilities'
nb->facilities = x25_subscr.facilities;
^ ~~~~~~~~~~~~~~~~~~~~~
2 errors generated.

vim +1709 net/x25/af_x25.c

1678
1679 #ifdef CONFIG_COMPAT
1680 static int compat_x25_subscr_ioctl(unsigned int cmd,
1681 struct compat_x25_subscrip_struct __user *x25_subscr32)
1682 {
1683 struct compat_x25_subscrip_struct x25_subscr;
1684 struct x25_neigh *nb;
1685 struct net_device *dev;
1686 int rc = -EINVAL;
1687
1688 if (cmd != SIOCX25GSUBSCRIP && cmd != SIOCX25SSUBSCRIP)
1689 goto out;
1690
1691 rc = -EFAULT;
1692 if (copy_from_user(&x25_subscr, x25_subscr32, sizeof(*x25_subscr32)))
1693 goto out;
1694
1695 rc = -EINVAL;
1696 dev = x25_dev_get(x25_subscr.device);
1697 if (dev == NULL)
1698 goto out;
1699
1700 nb = x25_get_neigh(dev);
1701 if (nb == NULL)
1702 goto out_dev_put;
1703
1704 if (cmd == SIOCX25GSUBSCRIP) {
1705 read_lock_bh(&x25_neigh_list_lock);
1706 x25_subscr.extended = nb->extended;
1707 x25_subscr.dce = nb->dce;
1708 x25_subscr.lc = nb->lc;
> 1709 x25_subscr.facilities = nb->facilities;
1710 x25_subscr.t20 = nb->t20;
1711 x25_subscr.global_facil_mask = nb->global_facil_mask;
1712 read_unlock_bh(&x25_neigh_list_lock);
1713 rc = copy_to_user(x25_subscr32, &x25_subscr,
1714 sizeof(*x25_subscr32)) ? -EFAULT : 0;
1715 } else {
1716 rc = -EINVAL;
1717
1718 if (dev->flags & IFF_UP)
1719 return -EBUSY;
1720
1721 if (x25_subscr.extended != 0 && x25_subscr.extended != 1)
1722 goto out_dev_and_neigh_put;
1723 if (x25_subscr.dce != 0 && x25_subscr.dce != 1)
1724 goto out_dev_and_neigh_put;
1725 if (x25_subscr.lc < 1 || x25_subscr.lc > 4095)
1726 goto out_dev_and_neigh_put;
1727 if (x25_subscr.facilities.pacsize_in < X25_PS16 ||
1728 x25_subscr.facilities.pacsize_in > X25_PS4096)
1729 goto out_dev_and_neigh_put;
1730 if (x25_subscr.facilities.pacsize_out < X25_PS16 ||
1731 x25_subscr.facilities.pacsize_out > X25_PS4096)
1732 goto out_dev_and_neigh_put;
1733 if (x25_subscr.facilities.winsize_in < 1 ||
1734 x25_subscr.facilities.winsize_in > 127)
1735 goto out_dev_and_neigh_put;
1736 if (x25_subscr.facilities.throughput) {
1737 int out = x25_subscr.facilities.throughput & 0xf0;
1738 int in = x25_subscr.facilities.throughput & 0x0f;
1739 if (!out)
1740 x25_subscr.facilities.throughput |=
1741 X25_DEFAULT_THROUGHPUT << 4;
1742 else if (out < 0x30 || out > 0xD0)
1743 goto out_dev_and_neigh_put;
1744 if (!in)
1745 x25_subscr.facilities.throughput |=
1746 X25_DEFAULT_THROUGHPUT;
1747 else if (in < 0x03 || in > 0x0D)
1748 goto out_dev_and_neigh_put;
1749 }
1750 if (x25_subscr.facilities.reverse &&
1751 (x25_subscr.facilities.reverse & 0x81) != 0x81)
1752 goto out_dev_and_neigh_put;
1753 if (x25_subscr.t20 < 1 * HZ || x25_subscr.t20 > 300 * HZ)
1754 goto out_dev_and_neigh_put;
1755
1756 rc = 0;
1757 write_lock_bh(&x25_neigh_list_lock);
1758 nb->extended = x25_subscr.extended;
1759 nb->dce = x25_subscr.dce;
1760 nb->lc = x25_subscr.lc;
> 1761 nb->facilities = x25_subscr.facilities;
1762 nb->t20 = x25_subscr.t20;
1763 nb->global_facil_mask = x25_subscr.global_facil_mask;
1764 write_unlock_bh(&x25_neigh_list_lock);
1765 }
1766 dev_put(dev);
1767
1768 x25_neigh_put(nb);
1769 out:
1770 return rc;
1771 out_dev_and_neigh_put:
1772 x25_neigh_put(nb);
1773 out_dev_put:
1774 dev_put(dev);
1775 goto out;
1776 }
1777

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]


Attachments:
(No filename) (6.03 kB)
.config.gz (31.37 kB)
Download all attachments