diff options
Diffstat (limited to 'net/x25')
-rw-r--r-- | net/x25/Makefile | 2 | ||||
-rw-r--r-- | net/x25/af_x25.c | 96 | ||||
-rw-r--r-- | net/x25/sysctl_net_x25.c | 18 | ||||
-rw-r--r-- | net/x25/x25_dev.c | 19 | ||||
-rw-r--r-- | net/x25/x25_facilities.c | 10 | ||||
-rw-r--r-- | net/x25/x25_forward.c | 163 | ||||
-rw-r--r-- | net/x25/x25_in.c | 8 | ||||
-rw-r--r-- | net/x25/x25_link.c | 6 | ||||
-rw-r--r-- | net/x25/x25_out.c | 10 | ||||
-rw-r--r-- | net/x25/x25_proc.c | 110 | ||||
-rw-r--r-- | net/x25/x25_route.c | 5 | ||||
-rw-r--r-- | net/x25/x25_timer.c | 6 |
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) { |