diff options
-rw-r--r-- | include/net/x25.h | 17 | ||||
-rw-r--r-- | net/x25/Makefile | 2 | ||||
-rw-r--r-- | net/x25/af_x25.c | 30 | ||||
-rw-r--r-- | net/x25/x25_dev.c | 13 | ||||
-rw-r--r-- | net/x25/x25_forward.c | 163 | ||||
-rw-r--r-- | net/x25/x25_route.c | 3 |
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 | ||
164 | struct 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 | |||
164 | static inline struct x25_sock *x25_sk(const struct sock *sk) | 172 | static 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 *); |
199 | extern void x25_limit_facilities(struct x25_facilities *, struct x25_neigh *); | 207 | extern void x25_limit_facilities(struct x25_facilities *, struct x25_neigh *); |
200 | 208 | ||
209 | /* x25_forward.c */ | ||
210 | extern void x25_clear_forward_by_lci(unsigned int lci); | ||
211 | extern void x25_clear_forward_by_dev(struct net_device *); | ||
212 | extern int x25_forward_data(int, struct x25_neigh *, struct sk_buff *); | ||
213 | extern int x25_forward_call(struct x25_address *, struct x25_neigh *, | ||
214 | struct sk_buff *, int); | ||
215 | |||
201 | /* x25_in.c */ | 216 | /* x25_in.c */ |
202 | extern int x25_process_rx_frame(struct sock *, struct sk_buff *); | 217 | extern int x25_process_rx_frame(struct sock *, struct sk_buff *); |
203 | extern int x25_backlog_rcv(struct sock *, struct sk_buff *); | 218 | extern int x25_backlog_rcv(struct sock *, struct sk_buff *); |
@@ -282,6 +297,8 @@ extern struct hlist_head x25_list; | |||
282 | extern rwlock_t x25_list_lock; | 297 | extern rwlock_t x25_list_lock; |
283 | extern struct list_head x25_route_list; | 298 | extern struct list_head x25_route_list; |
284 | extern rwlock_t x25_route_list_lock; | 299 | extern rwlock_t x25_route_list_lock; |
300 | extern struct list_head x25_forward_list; | ||
301 | extern rwlock_t x25_forward_list_lock; | ||
285 | 302 | ||
286 | extern int x25_proc_init(void); | 303 | extern int x25_proc_init(void); |
287 | extern void x25_proc_exit(void); | 304 | extern 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 | ||
7 | x25-y := af_x25.o x25_dev.o x25_facilities.o x25_in.o \ | 7 | x25-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 |
10 | x25-$(CONFIG_SYSCTL) += sysctl_net_x25.o | 10 | x25-$(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 | ||
1603 | static int __init x25_init(void) | 1623 | static 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 | |||
15 | struct list_head x25_forward_list = LIST_HEAD_INIT(x25_forward_list); | ||
16 | DEFINE_RWLOCK(x25_forward_list_lock); | ||
17 | |||
18 | int 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 | |||
82 | out_put_nb: | ||
83 | x25_neigh_put(neigh_new); | ||
84 | |||
85 | out_put_route: | ||
86 | x25_route_put(rt); | ||
87 | return rc; | ||
88 | } | ||
89 | |||
90 | |||
91 | int 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; | ||
126 | out: | ||
127 | return rc; | ||
128 | } | ||
129 | |||
130 | void 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 | |||
148 | void 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 | /* |