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 | /* |
