aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Hendry <andrew.hendry@gmail.com>2007-02-08 16:34:02 -0500
committerDavid S. Miller <davem@davemloft.net>2007-02-08 16:34:02 -0500
commit95a9dc4390c8215d922e0ca2ebb95279261fe795 (patch)
tree8b4be0c3a672ebd30d2777227e9a466819483ab8
parente610e679dd0057403c96cd31f8739792780732ee (diff)
[X.25]: Add call forwarding
Adds call forwarding to X.25, allowing it to operate like an X.25 router. Useful if one needs to manipulate X.25 traffic with tools like tc. This is an update/cleanup based off a patch submitted by Daniel Ferenci a few years ago. Thanks Alan for the feedback. Added the null check to the clones. Moved the skb_clone's into the forwarding functions. Worked ok with Cisco XoT, linux X.25 back to back, and some old NTUs/PADs. Signed-off-by: Andrew Hendry <andrew.hendry@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/x25.h17
-rw-r--r--net/x25/Makefile2
-rw-r--r--net/x25/af_x25.c30
-rw-r--r--net/x25/x25_dev.c13
-rw-r--r--net/x25/x25_forward.c163
-rw-r--r--net/x25/x25_route.c3
6 files changed, 220 insertions, 8 deletions
diff --git a/include/net/x25.h b/include/net/x25.h
index e47fe440d9d7..3b1190514d92 100644
--- a/include/net/x25.h
+++ b/include/net/x25.h
@@ -161,6 +161,14 @@ struct x25_sock {
161 unsigned long vc_facil_mask; /* inc_call facilities mask */ 161 unsigned long vc_facil_mask; /* inc_call facilities mask */
162}; 162};
163 163
164struct x25_forward {
165 struct list_head node;
166 unsigned int lci;
167 struct net_device *dev1;
168 struct net_device *dev2;
169 atomic_t refcnt;
170};
171
164static inline struct x25_sock *x25_sk(const struct sock *sk) 172static inline struct x25_sock *x25_sk(const struct sock *sk)
165{ 173{
166 return (struct x25_sock *)sk; 174 return (struct x25_sock *)sk;
@@ -198,6 +206,13 @@ extern int x25_negotiate_facilities(struct sk_buff *, struct sock *,
198 struct x25_dte_facilities *); 206 struct x25_dte_facilities *);
199extern void x25_limit_facilities(struct x25_facilities *, struct x25_neigh *); 207extern void x25_limit_facilities(struct x25_facilities *, struct x25_neigh *);
200 208
209/* x25_forward.c */
210extern void x25_clear_forward_by_lci(unsigned int lci);
211extern void x25_clear_forward_by_dev(struct net_device *);
212extern int x25_forward_data(int, struct x25_neigh *, struct sk_buff *);
213extern int x25_forward_call(struct x25_address *, struct x25_neigh *,
214 struct sk_buff *, int);
215
201/* x25_in.c */ 216/* x25_in.c */
202extern int x25_process_rx_frame(struct sock *, struct sk_buff *); 217extern int x25_process_rx_frame(struct sock *, struct sk_buff *);
203extern int x25_backlog_rcv(struct sock *, struct sk_buff *); 218extern int x25_backlog_rcv(struct sock *, struct sk_buff *);
@@ -282,6 +297,8 @@ extern struct hlist_head x25_list;
282extern rwlock_t x25_list_lock; 297extern rwlock_t x25_list_lock;
283extern struct list_head x25_route_list; 298extern struct list_head x25_route_list;
284extern rwlock_t x25_route_list_lock; 299extern rwlock_t x25_route_list_lock;
300extern struct list_head x25_forward_list;
301extern rwlock_t x25_forward_list_lock;
285 302
286extern int x25_proc_init(void); 303extern int x25_proc_init(void);
287extern void x25_proc_exit(void); 304extern void x25_proc_exit(void);
diff --git a/net/x25/Makefile b/net/x25/Makefile
index 587a71aa411d..a2c34ab6f194 100644
--- a/net/x25/Makefile
+++ b/net/x25/Makefile
@@ -6,5 +6,5 @@ obj-$(CONFIG_X25) += x25.o
6 6
7x25-y := af_x25.o x25_dev.o x25_facilities.o x25_in.o \ 7x25-y := af_x25.o x25_dev.o x25_facilities.o x25_in.o \
8 x25_link.o x25_out.o x25_route.o x25_subr.o \ 8 x25_link.o x25_out.o x25_route.o x25_subr.o \
9 x25_timer.o x25_proc.o 9 x25_timer.o x25_proc.o x25_forward.o
10x25-$(CONFIG_SYSCTL) += sysctl_net_x25.o 10x25-$(CONFIG_SYSCTL) += sysctl_net_x25.o
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index b5c80b189902..0872025821c5 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -846,7 +846,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
846 struct x25_address source_addr, dest_addr; 846 struct x25_address source_addr, dest_addr;
847 struct x25_facilities facilities; 847 struct x25_facilities facilities;
848 struct x25_dte_facilities dte_facilities; 848 struct x25_dte_facilities dte_facilities;
849 int len, rc; 849 int len, addr_len, rc;
850 850
851 /* 851 /*
852 * Remove the LCI and frame type. 852 * Remove the LCI and frame type.
@@ -857,7 +857,8 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
857 * Extract the X.25 addresses and convert them to ASCII strings, 857 * Extract the X.25 addresses and convert them to ASCII strings,
858 * and remove them. 858 * and remove them.
859 */ 859 */
860 skb_pull(skb, x25_addr_ntoa(skb->data, &source_addr, &dest_addr)); 860 addr_len = x25_addr_ntoa(skb->data, &source_addr, &dest_addr);
861 skb_pull(skb, addr_len);
861 862
862 /* 863 /*
863 * Get the length of the facilities, skip past them for the moment 864 * Get the length of the facilities, skip past them for the moment
@@ -873,11 +874,27 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
873 sk = x25_find_listener(&source_addr,skb); 874 sk = x25_find_listener(&source_addr,skb);
874 skb_push(skb,len); 875 skb_push(skb,len);
875 876
877 if (sk != NULL && sk_acceptq_is_full(sk)) {
878 goto out_sock_put;
879 }
880
876 /* 881 /*
877 * We can't accept the Call Request. 882 * We dont have any listeners for this incoming call.
883 * Try forwarding it.
878 */ 884 */
879 if (sk == NULL || sk_acceptq_is_full(sk)) 885 if (sk == NULL) {
880 goto out_clear_request; 886 skb_push(skb, addr_len + X25_STD_MIN_LEN);
887 if (x25_forward_call(&dest_addr, nb, skb, lci) > 0)
888 {
889 /* Call was forwarded, dont process it any more */
890 kfree_skb(skb);
891 rc = 1;
892 goto out;
893 } else {
894 /* No listeners, can't forward, clear the call */
895 goto out_clear_request;
896 }
897 }
881 898
882 /* 899 /*
883 * Try to reach a compromise on the requested facilities. 900 * Try to reach a compromise on the requested facilities.
@@ -1598,6 +1615,9 @@ void x25_kill_by_neigh(struct x25_neigh *nb)
1598 x25_disconnect(s, ENETUNREACH, 0, 0); 1615 x25_disconnect(s, ENETUNREACH, 0, 0);
1599 1616
1600 write_unlock_bh(&x25_list_lock); 1617 write_unlock_bh(&x25_list_lock);
1618
1619 /* Remove any related forwards */
1620 x25_clear_forward_by_dev(nb->dev);
1601} 1621}
1602 1622
1603static int __init x25_init(void) 1623static int __init x25_init(void)
diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c
index 328d80f000ad..f099fd6a7c0e 100644
--- a/net/x25/x25_dev.c
+++ b/net/x25/x25_dev.c
@@ -67,9 +67,18 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)
67 return x25_rx_call_request(skb, nb, lci); 67 return x25_rx_call_request(skb, nb, lci);
68 68
69 /* 69 /*
70 * Its not a Call Request, nor is it a control frame. 70 * Its not a Call Request, nor is it a control frame.
71 * Let caller throw it away. 71 * Can we forward it?
72 */ 72 */
73
74 if (x25_forward_data(lci, nb, skb)) {
75 if (frametype == X25_CLEAR_CONFIRMATION) {
76 x25_clear_forward_by_lci(lci);
77 }
78 kfree_skb(skb);
79 return 1;
80 }
81
73/* 82/*
74 x25_transmit_clear_request(nb, lci, 0x0D); 83 x25_transmit_clear_request(nb, lci, 0x0D);
75*/ 84*/
diff --git a/net/x25/x25_forward.c b/net/x25/x25_forward.c
new file mode 100644
index 000000000000..d339e0c810a8
--- /dev/null
+++ b/net/x25/x25_forward.c
@@ -0,0 +1,163 @@
1/*
2 * This module:
3 * This module is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License
5 * as published by the Free Software Foundation; either version
6 * 2 of the License, or (at your option) any later version.
7 *
8 * History
9 * 03-01-2007 Added forwarding for x.25 Andrew Hendry
10 */
11#include <linux/if_arp.h>
12#include <linux/init.h>
13#include <net/x25.h>
14
15struct list_head x25_forward_list = LIST_HEAD_INIT(x25_forward_list);
16DEFINE_RWLOCK(x25_forward_list_lock);
17
18int x25_forward_call(struct x25_address *dest_addr, struct x25_neigh *from,
19 struct sk_buff *skb, int lci)
20{
21 struct x25_route *rt;
22 struct x25_neigh *neigh_new = NULL;
23 struct list_head *entry;
24 struct x25_forward *x25_frwd, *new_frwd;
25 struct sk_buff *skbn;
26 short same_lci = 0;
27 int rc = 0;
28
29 if ((rt = x25_get_route(dest_addr)) != NULL) {
30
31 if ((neigh_new = x25_get_neigh(rt->dev)) == NULL) {
32 /* This shouldnt happen, if it occurs somehow
33 * do something sensible
34 */
35 goto out_put_route;
36 }
37
38 /* Avoid a loop. This is the normal exit path for a
39 * system with only one x.25 iface and default route
40 */
41 if (rt->dev == from->dev) {
42 goto out_put_nb;
43 }
44
45 /* Remote end sending a call request on an already
46 * established LCI? It shouldnt happen, just in case..
47 */
48 read_lock_bh(&x25_forward_list_lock);
49 list_for_each(entry, &x25_forward_list) {
50 x25_frwd = list_entry(entry, struct x25_forward, node);
51 if (x25_frwd->lci == lci) {
52 printk(KERN_WARNING "X.25: call request for lci which is already registered!, transmitting but not registering new pair\n");
53 same_lci = 1;
54 }
55 }
56 read_unlock_bh(&x25_forward_list_lock);
57
58 /* Save the forwarding details for future traffic */
59 if (!same_lci){
60 if ((new_frwd = kmalloc(sizeof(struct x25_forward),
61 GFP_ATOMIC)) == NULL){
62 rc = -ENOMEM;
63 goto out_put_nb;
64 }
65 new_frwd->lci = lci;
66 new_frwd->dev1 = rt->dev;
67 new_frwd->dev2 = from->dev;
68 write_lock_bh(&x25_forward_list_lock);
69 list_add(&new_frwd->node, &x25_forward_list);
70 write_unlock_bh(&x25_forward_list_lock);
71 }
72
73 /* Forward the call request */
74 if ( (skbn = skb_clone(skb, GFP_ATOMIC)) == NULL){
75 goto out_put_nb;
76 }
77 x25_transmit_link(skbn, neigh_new);
78 rc = 1;
79 }
80
81
82out_put_nb:
83 x25_neigh_put(neigh_new);
84
85out_put_route:
86 x25_route_put(rt);
87 return rc;
88}
89
90
91int x25_forward_data(int lci, struct x25_neigh *from, struct sk_buff *skb) {
92
93 struct x25_forward *frwd;
94 struct list_head *entry;
95 struct net_device *peer = NULL;
96 struct x25_neigh *nb;
97 struct sk_buff *skbn;
98 int rc = 0;
99
100 read_lock_bh(&x25_forward_list_lock);
101 list_for_each(entry, &x25_forward_list) {
102 frwd = list_entry(entry, struct x25_forward, node);
103 if (frwd->lci == lci) {
104 /* The call is established, either side can send */
105 if (from->dev == frwd->dev1) {
106 peer = frwd->dev2;
107 } else {
108 peer = frwd->dev1;
109 }
110 break;
111 }
112 }
113 read_unlock_bh(&x25_forward_list_lock);
114
115 if ( (nb = x25_get_neigh(peer)) == NULL)
116 goto out;
117
118 if ( (skbn = pskb_copy(skb, GFP_ATOMIC)) == NULL){
119 goto out;
120
121 }
122 x25_transmit_link(skbn, nb);
123
124 x25_neigh_put(nb);
125 rc = 1;
126out:
127 return rc;
128}
129
130void x25_clear_forward_by_lci(unsigned int lci)
131{
132 struct x25_forward *fwd;
133 struct list_head *entry, *tmp;
134
135 write_lock_bh(&x25_forward_list_lock);
136
137 list_for_each_safe(entry, tmp, &x25_forward_list) {
138 fwd = list_entry(entry, struct x25_forward, node);
139 if (fwd->lci == lci) {
140 list_del(&fwd->node);
141 kfree(fwd);
142 }
143 }
144 write_unlock_bh(&x25_forward_list_lock);
145}
146
147
148void x25_clear_forward_by_dev(struct net_device *dev)
149{
150 struct x25_forward *fwd;
151 struct list_head *entry, *tmp;
152
153 write_lock_bh(&x25_forward_list_lock);
154
155 list_for_each_safe(entry, tmp, &x25_forward_list) {
156 fwd = list_entry(entry, struct x25_forward, node);
157 if ((fwd->dev1 == dev) || (fwd->dev2 == dev)){
158 list_del(&fwd->node);
159 kfree(fwd);
160 }
161 }
162 write_unlock_bh(&x25_forward_list_lock);
163}
diff --git a/net/x25/x25_route.c b/net/x25/x25_route.c
index 2a3fe986b245..883a848bca5b 100644
--- a/net/x25/x25_route.c
+++ b/net/x25/x25_route.c
@@ -119,6 +119,9 @@ void x25_route_device_down(struct net_device *dev)
119 __x25_remove_route(rt); 119 __x25_remove_route(rt);
120 } 120 }
121 write_unlock_bh(&x25_route_list_lock); 121 write_unlock_bh(&x25_route_list_lock);
122
123 /* Remove any related forwarding */
124 x25_clear_forward_by_dev(dev);
122} 125}
123 126
124/* 127/*