summaryrefslogtreecommitdiffstats
path: root/net/x25
diff options
context:
space:
mode:
Diffstat (limited to 'net/x25')
-rw-r--r--net/x25/Makefile2
-rw-r--r--net/x25/af_x25.c96
-rw-r--r--net/x25/sysctl_net_x25.c18
-rw-r--r--net/x25/x25_dev.c19
-rw-r--r--net/x25/x25_facilities.c10
-rw-r--r--net/x25/x25_forward.c163
-rw-r--r--net/x25/x25_in.c8
-rw-r--r--net/x25/x25_link.c6
-rw-r--r--net/x25/x25_out.c10
-rw-r--r--net/x25/x25_proc.c110
-rw-r--r--net/x25/x25_route.c5
-rw-r--r--net/x25/x25_timer.c6
12 files changed, 378 insertions, 75 deletions
diff --git a/net/x25/Makefile b/net/x25/Makefile
index 587a71aa411..a2c34ab6f19 100644
--- a/net/x25/Makefile
+++ b/net/x25/Makefile
@@ -6,5 +6,5 @@ obj-$(CONFIG_X25) += x25.o
x25-y := af_x25.o x25_dev.o x25_facilities.o x25_in.o \
x25_link.o x25_out.o x25_route.o x25_subr.o \
- x25_timer.o x25_proc.o
+ x25_timer.o x25_proc.o x25_forward.o
x25-$(CONFIG_SYSCTL) += sysctl_net_x25.o
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index b5c80b18990..e62ba41b05c 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -3,7 +3,7 @@
*
* This is ALPHA test software. This code may break your machine,
* randomly fail to work with new releases, misbehave and/or generally
- * screw up. It might even work.
+ * screw up. It might even work.
*
* This code REQUIRES 2.1.15 or higher
*
@@ -18,11 +18,11 @@
* X.25 002 Jonathan Naylor Centralised disconnect handling.
* New timer architecture.
* 2000-03-11 Henner Eisen MSG_EOR handling more POSIX compliant.
- * 2000-03-22 Daniela Squassoni Allowed disabling/enabling of
- * facilities negotiation and increased
+ * 2000-03-22 Daniela Squassoni Allowed disabling/enabling of
+ * facilities negotiation and increased
* the throughput upper limit.
* 2000-08-27 Arnaldo C. Melo s/suser/capable/ + micro cleanups
- * 2000-09-04 Henner Eisen Set sock->state in x25_accept().
+ * 2000-09-04 Henner Eisen Set sock->state in x25_accept().
* Fixed x25_output() related skb leakage.
* 2000-10-02 Henner Eisen Made x25_kick() single threaded per socket.
* 2000-10-27 Henner Eisen MSG_DONTWAIT for fragment allocation.
@@ -63,6 +63,7 @@ int sysctl_x25_call_request_timeout = X25_DEFAULT_T21;
int sysctl_x25_reset_request_timeout = X25_DEFAULT_T22;
int sysctl_x25_clear_request_timeout = X25_DEFAULT_T23;
int sysctl_x25_ack_holdback_timeout = X25_DEFAULT_T2;
+int sysctl_x25_forward = 0;
HLIST_HEAD(x25_list);
DEFINE_RWLOCK(x25_list_lock);
@@ -255,8 +256,8 @@ static struct sock *x25_find_listener(struct x25_address *addr,
* call user data vs this sockets call user data
*/
if(skb->len > 0 && x25_sk(s)->cudmatchlength > 0) {
- if((memcmp(x25_sk(s)->calluserdata.cuddata,
- skb->data,
+ if((memcmp(x25_sk(s)->calluserdata.cuddata,
+ skb->data,
x25_sk(s)->cudmatchlength)) == 0) {
sock_hold(s);
goto found;
@@ -420,7 +421,7 @@ static int x25_getsockopt(struct socket *sock, int level, int optname,
{
struct sock *sk = sock->sk;
int val, len, rc = -ENOPROTOOPT;
-
+
if (level != SOL_X25 || optname != X25_QBITINCL)
goto out;
@@ -433,7 +434,7 @@ static int x25_getsockopt(struct socket *sock, int level, int optname,
rc = -EINVAL;
if (len < 0)
goto out;
-
+
rc = -EFAULT;
if (put_user(len, optlen))
goto out;
@@ -522,12 +523,12 @@ static int x25_create(struct socket *sock, int protocol)
x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE;
x25->facilities.throughput = X25_DEFAULT_THROUGHPUT;
x25->facilities.reverse = X25_DEFAULT_REVERSE;
- x25->dte_facilities.calling_len = 0;
- x25->dte_facilities.called_len = 0;
- memset(x25->dte_facilities.called_ae, '\0',
- sizeof(x25->dte_facilities.called_ae));
- memset(x25->dte_facilities.calling_ae, '\0',
- sizeof(x25->dte_facilities.calling_ae));
+ x25->dte_facilities.calling_len = 0;
+ x25->dte_facilities.called_len = 0;
+ memset(x25->dte_facilities.called_ae, '\0',
+ sizeof(x25->dte_facilities.called_ae));
+ memset(x25->dte_facilities.calling_ae, '\0',
+ sizeof(x25->dte_facilities.calling_ae));
rc = 0;
out:
@@ -607,7 +608,7 @@ static int x25_release(struct socket *sock)
break;
}
- sock->sk = NULL;
+ sock->sk = NULL;
sk->sk_socket = NULL; /* Not used, but we should do this */
out:
return 0;
@@ -634,7 +635,7 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
static int x25_wait_for_connection_establishment(struct sock *sk)
{
DECLARE_WAITQUEUE(wait, current);
- int rc;
+ int rc;
add_wait_queue_exclusive(sk->sk_sleep, &wait);
for (;;) {
@@ -685,7 +686,7 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr,
if (sk->sk_state == TCP_ESTABLISHED)
goto out;
- sk->sk_state = TCP_CLOSE;
+ sk->sk_state = TCP_CLOSE;
sock->state = SS_UNCONNECTED;
rc = -EINVAL;
@@ -777,7 +778,7 @@ static int x25_wait_for_data(struct sock *sk, long timeout)
remove_wait_queue(sk->sk_sleep, &wait);
return rc;
}
-
+
static int x25_accept(struct socket *sock, struct socket *newsock, int flags)
{
struct sock *sk = sock->sk;
@@ -836,7 +837,7 @@ static int x25_getname(struct socket *sock, struct sockaddr *uaddr,
return 0;
}
-
+
int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
unsigned int lci)
{
@@ -846,7 +847,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
struct x25_address source_addr, dest_addr;
struct x25_facilities facilities;
struct x25_dte_facilities dte_facilities;
- int len, rc;
+ int len, addr_len, rc;
/*
* Remove the LCI and frame type.
@@ -857,7 +858,8 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
* Extract the X.25 addresses and convert them to ASCII strings,
* and remove them.
*/
- skb_pull(skb, x25_addr_ntoa(skb->data, &source_addr, &dest_addr));
+ addr_len = x25_addr_ntoa(skb->data, &source_addr, &dest_addr);
+ skb_pull(skb, addr_len);
/*
* Get the length of the facilities, skip past them for the moment
@@ -873,11 +875,28 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
sk = x25_find_listener(&source_addr,skb);
skb_push(skb,len);
+ if (sk != NULL && sk_acceptq_is_full(sk)) {
+ goto out_sock_put;
+ }
+
/*
- * We can't accept the Call Request.
+ * We dont have any listeners for this incoming call.
+ * Try forwarding it.
*/
- if (sk == NULL || sk_acceptq_is_full(sk))
- goto out_clear_request;
+ if (sk == NULL) {
+ skb_push(skb, addr_len + X25_STD_MIN_LEN);
+ if (sysctl_x25_forward &&
+ x25_forward_call(&dest_addr, nb, skb, lci) > 0)
+ {
+ /* Call was forwarded, dont process it any more */
+ kfree_skb(skb);
+ rc = 1;
+ goto out;
+ } else {
+ /* No listeners, can't forward, clear the call */
+ goto out_clear_request;
+ }
+ }
/*
* Try to reach a compromise on the requested facilities.
@@ -1101,7 +1120,7 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
if (msg->msg_flags & MSG_OOB)
skb_queue_tail(&x25->interrupt_out_queue, skb);
else {
- len = x25_output(sk, skb);
+ len = x25_output(sk, skb);
if (len < 0)
kfree_skb(skb);
else if (x25->qbitincl)
@@ -1200,7 +1219,7 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
msg->msg_flags |= MSG_TRUNC;
}
- /* Currently, each datagram always contains a complete record */
+ /* Currently, each datagram always contains a complete record */
msg->msg_flags |= MSG_EOR;
rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
@@ -1258,8 +1277,8 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case SIOCGSTAMP:
rc = -EINVAL;
if (sk)
- rc = sock_get_timestamp(sk,
- (struct timeval __user *)argp);
+ rc = sock_get_timestamp(sk,
+ (struct timeval __user *)argp);
break;
case SIOCGIFADDR:
case SIOCSIFADDR:
@@ -1327,17 +1346,17 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
}
case SIOCX25GDTEFACILITIES: {
- rc = copy_to_user(argp, &x25->dte_facilities,
+ rc = copy_to_user(argp, &x25->dte_facilities,
sizeof(x25->dte_facilities));
if (rc)
rc = -EFAULT;
- break;
- }
+ break;
+ }
- case SIOCX25SDTEFACILITIES: {
- struct x25_dte_facilities dtefacs;
- rc = -EFAULT;
- if (copy_from_user(&dtefacs, argp, sizeof(dtefacs)))
+ case SIOCX25SDTEFACILITIES: {
+ struct x25_dte_facilities dtefacs;
+ rc = -EFAULT;
+ if (copy_from_user(&dtefacs, argp, sizeof(dtefacs)))
break;
rc = -EINVAL;
if (sk->sk_state != TCP_LISTEN &&
@@ -1395,7 +1414,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
if (copy_from_user(&sub_addr, argp,
sizeof(sub_addr)))
break;
- rc = -EINVAL;
+ rc = -EINVAL;
if(sub_addr.cudmatchlength > X25_MAX_CUD_LEN)
break;
x25->cudmatchlength = sub_addr.cudmatchlength;
@@ -1424,7 +1443,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
break;
}
- default:
+ default:
rc = -ENOIOCTLCMD;
break;
}
@@ -1598,6 +1617,9 @@ void x25_kill_by_neigh(struct x25_neigh *nb)
x25_disconnect(s, ENETUNREACH, 0, 0);
write_unlock_bh(&x25_list_lock);
+
+ /* Remove any related forwards */
+ x25_clear_forward_by_dev(nb->dev);
}
static int __init x25_init(void)
diff --git a/net/x25/sysctl_net_x25.c b/net/x25/sysctl_net_x25.c
index aabda59c824..5f631061c22 100644
--- a/net/x25/sysctl_net_x25.c
+++ b/net/x25/sysctl_net_x25.c
@@ -18,7 +18,7 @@ static int max_timer[] = { 300 * HZ };
static struct ctl_table_header *x25_table_header;
static struct ctl_table x25_table[] = {
- {
+ {
.ctl_name = NET_X25_RESTART_REQUEST_TIMEOUT,
.procname = "restart_request_timeout",
.data = &sysctl_x25_restart_request_timeout,
@@ -29,7 +29,7 @@ static struct ctl_table x25_table[] = {
.extra1 = &min_timer,
.extra2 = &max_timer,
},
- {
+ {
.ctl_name = NET_X25_CALL_REQUEST_TIMEOUT,
.procname = "call_request_timeout",
.data = &sysctl_x25_call_request_timeout,
@@ -40,7 +40,7 @@ static struct ctl_table x25_table[] = {
.extra1 = &min_timer,
.extra2 = &max_timer,
},
- {
+ {
.ctl_name = NET_X25_RESET_REQUEST_TIMEOUT,
.procname = "reset_request_timeout",
.data = &sysctl_x25_reset_request_timeout,
@@ -51,7 +51,7 @@ static struct ctl_table x25_table[] = {
.extra1 = &min_timer,
.extra2 = &max_timer,
},
- {
+ {
.ctl_name = NET_X25_CLEAR_REQUEST_TIMEOUT,
.procname = "clear_request_timeout",
.data = &sysctl_x25_clear_request_timeout,
@@ -62,7 +62,7 @@ static struct ctl_table x25_table[] = {
.extra1 = &min_timer,
.extra2 = &max_timer,
},
- {
+ {
.ctl_name = NET_X25_ACK_HOLD_BACK_TIMEOUT,
.procname = "acknowledgement_hold_back_timeout",
.data = &sysctl_x25_ack_holdback_timeout,
@@ -73,6 +73,14 @@ static struct ctl_table x25_table[] = {
.extra1 = &min_timer,
.extra2 = &max_timer,
},
+ {
+ .ctl_name = NET_X25_FORWARD,
+ .procname = "x25_forward",
+ .data = &sysctl_x25_forward,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
{ 0, },
};
diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c
index 328d80f000a..c7221de98a9 100644
--- a/net/x25/x25_dev.c
+++ b/net/x25/x25_dev.c
@@ -1,8 +1,8 @@
/*
* X.25 Packet Layer release 002
*
- * This is ALPHA test software. This code may break your machine, randomly fail to work with new
- * releases, misbehave and/or generally screw up. It might even work.
+ * This is ALPHA test software. This code may break your machine, randomly fail to work with new
+ * releases, misbehave and/or generally screw up. It might even work.
*
* This code REQUIRES 2.1.15 or higher
*
@@ -31,7 +31,7 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)
unsigned int lci;
frametype = skb->data[2];
- lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF);
+ lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF);
/*
* LCI of zero is always for us, and its always a link control
@@ -67,9 +67,18 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)
return x25_rx_call_request(skb, nb, lci);
/*
- * Its not a Call Request, nor is it a control frame.
- * Let caller throw it away.
+ * Its not a Call Request, nor is it a control frame.
+ * Can we forward it?
*/
+
+ if (x25_forward_data(lci, nb, skb)) {
+ if (frametype == X25_CLEAR_CONFIRMATION) {
+ x25_clear_forward_by_lci(lci);
+ }
+ kfree_skb(skb);
+ return 1;
+ }
+
/*
x25_transmit_clear_request(nb, lci, 0x0D);
*/
diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c
index 27f5cc7966f..dec404afa11 100644
--- a/net/x25/x25_facilities.c
+++ b/net/x25/x25_facilities.c
@@ -3,7 +3,7 @@
*
* This is ALPHA test software. This code may break your machine,
* randomly fail to work with new releases, misbehave and/or generally
- * screw up. It might even work.
+ * screw up. It might even work.
*
* This code REQUIRES 2.1.15 or higher
*
@@ -15,7 +15,7 @@
*
* History
* X.25 001 Split from x25_subr.c
- * mar/20/00 Daniela Squassoni Disabling/enabling of facilities
+ * mar/20/00 Daniela Squassoni Disabling/enabling of facilities
* negotiation.
* apr/14/05 Shaun Pereira - Allow fast select with no restriction
* on response.
@@ -125,8 +125,8 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
break;
case X25_FAC_CLASS_D:
switch (*p) {
- case X25_FAC_CALLING_AE:
- if (p[1] > X25_MAX_DTE_FACIL_LEN)
+ case X25_FAC_CALLING_AE:
+ if (p[1] > X25_MAX_DTE_FACIL_LEN)
break;
dte_facs->calling_len = p[2];
memcpy(dte_facs->calling_ae, &p[3], p[1] - 1);
@@ -293,7 +293,7 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk,
}
/*
- * Limit values of certain facilities according to the capability of the
+ * Limit values of certain facilities according to the capability of the
* currently attached x25 link.
*/
void x25_limit_facilities(struct x25_facilities *facilities,
diff --git a/net/x25/x25_forward.c b/net/x25/x25_forward.c
new file mode 100644
index 00000000000..d339e0c810a
--- /dev/null
+++ b/net/x25/x25_forward.c
@@ -0,0 +1,163 @@
+/*
+ * 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
+ * 03-01-2007 Added forwarding for x.25 Andrew Hendry
+ */
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <net/x25.h>
+
+struct list_head x25_forward_list = LIST_HEAD_INIT(x25_forward_list);
+DEFINE_RWLOCK(x25_forward_list_lock);
+
+int x25_forward_call(struct x25_address *dest_addr, struct x25_neigh *from,
+ struct sk_buff *skb, int lci)
+{
+ struct x25_route *rt;
+ struct x25_neigh *neigh_new = NULL;
+ struct list_head *entry;
+ struct x25_forward *x25_frwd, *new_frwd;
+ struct sk_buff *skbn;
+ short same_lci = 0;
+ int rc = 0;
+
+ if ((rt = x25_get_route(dest_addr)) != NULL) {
+
+ if ((neigh_new = x25_get_neigh(rt->dev)) == NULL) {
+ /* This shouldnt happen, if it occurs somehow
+ * do something sensible
+ */
+ goto out_put_route;
+ }
+
+ /* Avoid a loop. This is the normal exit path for a
+ * system with only one x.25 iface and default route
+ */
+ if (rt->dev == from->dev) {
+ goto out_put_nb;
+ }
+
+ /* Remote end sending a call request on an already
+ * established LCI? It shouldnt 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");
+ same_lci = 1;
+ }
+ }
+ read_unlock_bh(&x25_forward_list_lock);
+
+ /* Save the forwarding details for future traffic */
+ if (!same_lci){
+ if ((new_frwd = kmalloc(sizeof(struct x25_forward),
+ GFP_ATOMIC)) == NULL){
+ rc = -ENOMEM;
+ goto out_put_nb;
+ }
+ new_frwd->lci = lci;
+ new_frwd->dev1 = rt->dev;
+ new_frwd->dev2 = from->dev;
+ write_lock_bh(&x25_forward_list_lock);
+ list_add(&new_frwd->node, &x25_forward_list);
+ write_unlock_bh(&x25_forward_list_lock);
+ }
+
+ /* Forward the call request */
+ if ( (skbn = skb_clone(skb, GFP_ATOMIC)) == NULL){
+ goto out_put_nb;
+ }
+ x25_transmit_link(skbn, neigh_new);
+ rc = 1;
+ }
+
+
+out_put_nb:
+ x25_neigh_put(neigh_new);
+
+out_put_route:
+ x25_route_put(rt);
+ return rc;
+}
+
+
+int x25_forward_data(int lci, struct x25_neigh *from, struct sk_buff *skb) {
+
+ struct x25_forward *frwd;
+ struct list_head *entry;
+ struct net_device *peer = NULL;
+ struct x25_neigh *nb;
+ struct sk_buff *skbn;
+ int rc = 0;
+
+ read_lock_bh(&x25_forward_list_lock);
+ list_for_each(entry, &x25_forward_list) {
+ frwd = list_entry(entry, struct x25_forward, node);
+ if (frwd->lci == lci) {
+ /* The call is established, either side can send */
+ if (from->dev == frwd->dev1) {
+ peer = frwd->dev2;
+ } else {
+ peer = frwd->dev1;
+ }
+ break;
+ }
+ }
+ read_unlock_bh(&x25_forward_list_lock);
+
+ if ( (nb = x25_get_neigh(peer)) == NULL)
+ goto out;
+
+ if ( (skbn = pskb_copy(skb, GFP_ATOMIC)) == NULL){
+ goto out;
+
+ }
+ x25_transmit_link(skbn, nb);
+
+ x25_neigh_put(nb);
+ rc = 1;
+out:
+ return rc;
+}
+
+void x25_clear_forward_by_lci(unsigned int lci)
+{
+ struct x25_forward *fwd;
+ struct list_head *entry, *tmp;
+
+ write_lock_bh(&x25_forward_list_lock);
+
+ list_for_each_safe(entry, tmp, &x25_forward_list) {
+ fwd = list_entry(entry, struct x25_forward, node);
+ if (fwd->lci == lci) {
+ list_del(&fwd->node);
+ kfree(fwd);
+ }
+ }
+ write_unlock_bh(&x25_forward_list_lock);
+}
+
+
+void x25_clear_forward_by_dev(struct net_device *dev)
+{
+ struct x25_forward *fwd;
+ struct list_head *entry, *tmp;
+
+ write_lock_bh(&x25_forward_list_lock);
+
+ list_for_each_safe(entry, tmp, &x25_forward_list) {
+ fwd = list_entry(entry, struct x25_forward, node);
+ if ((fwd->dev1 == dev) || (fwd->dev2 == dev)){
+ list_del(&fwd->node);
+ kfree(fwd);
+ }
+ }
+ write_unlock_bh(&x25_forward_list_lock);
+}
diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
index eed50e10f09..c5239fcdefa 100644
--- a/net/x25/x25_in.c
+++ b/net/x25/x25_in.c
@@ -3,7 +3,7 @@
*
* This is ALPHA test software. This code may break your machine,
* randomly fail to work with new releases, misbehave and/or generally
- * screw up. It might even work.
+ * screw up. It might even work.
*
* This code REQUIRES 2.1.15 or higher
*
@@ -17,7 +17,7 @@
* X.25 001 Jonathan Naylor Started coding.
* X.25 002 Jonathan Naylor Centralised disconnection code.
* New timer architecture.
- * 2000-03-20 Daniela Squassoni Disabling/enabling of facilities
+ * 2000-03-20 Daniela Squassoni Disabling/enabling of facilities
* negotiation.
* 2000-11-10 Henner Eisen Check and reset for out-of-sequence
* i-frames.
@@ -67,7 +67,7 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
kfree_skb(skbo);
}
- x25->fraglen = 0;
+ x25->fraglen = 0;
}
skb_set_owner_r(skbn, sk);
@@ -167,7 +167,7 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
int queued = 0;
int modulus;
struct x25_sock *x25 = x25_sk(sk);
-
+
modulus = (x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS;
switch (frametype) {
diff --git a/net/x25/x25_link.c b/net/x25/x25_link.c
index 0a760fe6684..741ce95d4ad 100644
--- a/net/x25/x25_link.c
+++ b/net/x25/x25_link.c
@@ -3,7 +3,7 @@
*
* This is ALPHA test software. This code may break your machine,
* randomly fail to work with new releases, misbehave and/or generally
- * screw up. It might even work.
+ * screw up. It might even work.
*
* This code REQUIRES 2.1.15 or higher
*
@@ -16,7 +16,7 @@
* History
* X.25 001 Jonathan Naylor Started coding.
* X.25 002 Jonathan Naylor New timer architecture.
- * mar/20/00 Daniela Squassoni Disabling/enabling of facilities
+ * mar/20/00 Daniela Squassoni Disabling/enabling of facilities
* negotiation.
* 2000-09-04 Henner Eisen dev_hold() / dev_put() for x25_neigh.
*/
@@ -94,7 +94,7 @@ void x25_link_control(struct sk_buff *skb, struct x25_neigh *nb,
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);
diff --git a/net/x25/x25_out.c b/net/x25/x25_out.c
index a2e62cea819..6f573785391 100644
--- a/net/x25/x25_out.c
+++ b/net/x25/x25_out.c
@@ -3,7 +3,7 @@
*
* This is ALPHA test software. This code may break your machine,
* randomly fail to work with new releases, misbehave and/or generally
- * screw up. It might even work.
+ * screw up. It might even work.
*
* This code REQUIRES 2.1.15 or higher
*
@@ -78,7 +78,7 @@ int x25_output(struct sock *sk, struct sk_buff *skb)
"sent\n", err, sent);
return err;
}
-
+
skb_reserve(skbn, frontlen);
len = max_len > skb->len ? skb->len : max_len;
@@ -101,7 +101,7 @@ int x25_output(struct sock *sk, struct sk_buff *skb)
skb_queue_tail(&sk->sk_write_queue, skbn);
sent += len;
}
-
+
kfree_skb(skb);
} else {
skb_queue_tail(&sk->sk_write_queue, skb);
@@ -110,7 +110,7 @@ int x25_output(struct sock *sk, struct sk_buff *skb)
return sent;
}
-/*
+/*
* This procedure is passed a buffer descriptor for an iframe. It builds
* the rest of the control part of the frame and then writes it out.
*/
@@ -131,7 +131,7 @@ static void x25_send_iframe(struct sock *sk, struct sk_buff *skb)
skb->data[2] |= (x25->vr << 5) & 0xE0;
}
- x25_transmit_link(skb, x25->neighbour);
+ x25_transmit_link(skb, x25->neighbour);
}
void x25_kick(struct sock *sk)
diff --git a/net/x25/x25_proc.c b/net/x25/x25_proc.c
index a11837d361d..96001f0c64f 100644
--- a/net/x25/x25_proc.c
+++ b/net/x25/x25_proc.c
@@ -3,7 +3,7 @@
*
* This is ALPHA test software. This code may break your machine,
* randomly fail to work with new releases, misbehave and/or generally
- * screw up. It might even work.
+ * screw up. It might even work.
*
* This code REQUIRES 2.4 with seq_file support
*
@@ -62,7 +62,7 @@ static void *x25_seq_route_next(struct seq_file *seq, void *v, loff_t *pos)
rt = v;
if (rt->node.next != &x25_route_list)
rt = list_entry(rt->node.next, struct x25_route, node);
- else
+ else
rt = NULL;
out:
return rt;
@@ -88,7 +88,7 @@ static int x25_seq_route_show(struct seq_file *seq, void *v)
rt->dev ? rt->dev->name : "???");
out:
return 0;
-}
+}
static __inline__ struct sock *x25_get_socket_idx(loff_t pos)
{
@@ -163,7 +163,76 @@ static int x25_seq_socket_show(struct seq_file *seq, void *v)
s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : 0L);
out:
return 0;
-}
+}
+
+static __inline__ struct x25_forward *x25_get_forward_idx(loff_t pos)
+{
+ struct x25_forward *f;
+ struct list_head *entry;
+
+ list_for_each(entry, &x25_forward_list) {
+ f = list_entry(entry, struct x25_forward, node);
+ if (!pos--)
+ goto found;
+ }
+
+ f = NULL;
+found:
+ return f;
+}
+
+static void *x25_seq_forward_start(struct seq_file *seq, loff_t *pos)
+{
+ loff_t l = *pos;
+
+ read_lock_bh(&x25_forward_list_lock);
+ return l ? x25_get_forward_idx(--l) : SEQ_START_TOKEN;
+}
+
+static void *x25_seq_forward_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct x25_forward *f;
+
+ ++*pos;
+ if (v == SEQ_START_TOKEN) {
+ f = NULL;
+ if (!list_empty(&x25_forward_list))
+ f = list_entry(x25_forward_list.next,
+ struct x25_forward, node);
+ goto out;
+ }
+ f = v;
+ if (f->node.next != &x25_forward_list)
+ f = list_entry(f->node.next, struct x25_forward, node);
+ else
+ f = NULL;
+out:
+ return f;
+
+}
+
+static void x25_seq_forward_stop(struct seq_file *seq, void *v)
+{
+ read_unlock_bh(&x25_forward_list_lock);
+}
+
+static int x25_seq_forward_show(struct seq_file *seq, void *v)
+{
+ struct x25_forward *f;
+
+ if (v == SEQ_START_TOKEN) {
+ seq_printf(seq, "lci dev1 dev2\n");
+ goto out;
+ }
+
+ f = v;
+
+ seq_printf(seq, "%d %-10s %-10s\n",
+ f->lci, f->dev1->name, f->dev2->name);
+
+out:
+ return 0;
+}
static struct seq_operations x25_seq_route_ops = {
.start = x25_seq_route_start,
@@ -179,6 +248,13 @@ static struct seq_operations x25_seq_socket_ops = {
.show = x25_seq_socket_show,
};
+static struct seq_operations x25_seq_forward_ops = {
+ .start = x25_seq_forward_start,
+ .next = x25_seq_forward_next,
+ .stop = x25_seq_forward_stop,
+ .show = x25_seq_forward_show,
+};
+
static int x25_seq_socket_open(struct inode *inode, struct file *file)
{
return seq_open(file, &x25_seq_socket_ops);
@@ -189,7 +265,12 @@ static int x25_seq_route_open(struct inode *inode, struct file *file)
return seq_open(file, &x25_seq_route_ops);
}
-static struct file_operations x25_seq_socket_fops = {
+static int x25_seq_forward_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &x25_seq_forward_ops);
+}
+
+static const struct file_operations x25_seq_socket_fops = {
.owner = THIS_MODULE,
.open = x25_seq_socket_open,
.read = seq_read,
@@ -197,7 +278,7 @@ static struct file_operations x25_seq_socket_fops = {
.release = seq_release,
};
-static struct file_operations x25_seq_route_fops = {
+static const struct file_operations x25_seq_route_fops = {
.owner = THIS_MODULE,
.open = x25_seq_route_open,
.read = seq_read,
@@ -205,6 +286,14 @@ static struct file_operations x25_seq_route_fops = {
.release = seq_release,
};
+static 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)
@@ -225,9 +314,17 @@ int __init x25_proc_init(void)
if (!p)
goto out_socket;
p->proc_fops = &x25_seq_socket_fops;
+
+ p = create_proc_entry("forward", S_IRUGO, x25_proc_dir);
+ if (!p)
+ goto out_forward;
+ p->proc_fops = &x25_seq_forward_fops;
rc = 0;
+
out:
return rc;
+out_forward:
+ remove_proc_entry("socket", x25_proc_dir);
out_socket:
remove_proc_entry("route", x25_proc_dir);
out_route:
@@ -237,6 +334,7 @@ out_route:
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", proc_net);
diff --git a/net/x25/x25_route.c b/net/x25/x25_route.c
index 2a3fe986b24..060fcfaa2f4 100644
--- a/net/x25/x25_route.c
+++ b/net/x25/x25_route.c
@@ -3,7 +3,7 @@
*
* This is ALPHA test software. This code may break your machine,
* randomly fail to work with new releases, misbehave and/or generally
- * screw up. It might even work.
+ * screw up. It might even work.
*
* This code REQUIRES 2.1.15 or higher
*
@@ -119,6 +119,9 @@ void x25_route_device_down(struct net_device *dev)
__x25_remove_route(rt);
}
write_unlock_bh(&x25_route_list_lock);
+
+ /* Remove any related forwarding */
+ x25_clear_forward_by_dev(dev);
}
/*
diff --git a/net/x25/x25_timer.c b/net/x25/x25_timer.c
index 71ff3088f6f..2af190dc5b0 100644
--- a/net/x25/x25_timer.c
+++ b/net/x25/x25_timer.c
@@ -3,7 +3,7 @@
*
* This is ALPHA test software. This code may break your machine,
* randomly fail to work with new releases, misbehave and/or generally
- * screw up. It might even work.
+ * screw up. It might even work.
*
* This code REQUIRES 2.1.15 or higher
*
@@ -99,8 +99,8 @@ static void x25_heartbeat_expiry(unsigned long param)
{
struct sock *sk = (struct sock *)param;
- bh_lock_sock(sk);
- if (sock_owned_by_user(sk)) /* can currently only occur in state 3 */
+ bh_lock_sock(sk);
+ if (sock_owned_by_user(sk)) /* can currently only occur in state 3 */
goto restart_heartbeat;
switch (x25_sk(sk)->state) {