Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Andrew Hendry and committed by
David S. Miller
95a9dc43 e610e679

+220 -8
+17
include/net/x25.h
··· 161 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 172 static inline struct x25_sock *x25_sk(const struct sock *sk) 165 173 { 166 174 return (struct x25_sock *)sk; ··· 205 197 struct x25_facilities *, 206 198 struct x25_dte_facilities *); 207 199 extern void x25_limit_facilities(struct x25_facilities *, struct x25_neigh *); 200 + 201 + /* x25_forward.c */ 202 + extern void x25_clear_forward_by_lci(unsigned int lci); 203 + extern void x25_clear_forward_by_dev(struct net_device *); 204 + extern int x25_forward_data(int, struct x25_neigh *, struct sk_buff *); 205 + extern int x25_forward_call(struct x25_address *, struct x25_neigh *, 206 + struct sk_buff *, int); 208 207 209 208 /* x25_in.c */ 210 209 extern int x25_process_rx_frame(struct sock *, struct sk_buff *); ··· 297 282 extern rwlock_t x25_list_lock; 298 283 extern struct list_head x25_route_list; 299 284 extern rwlock_t x25_route_list_lock; 285 + extern struct list_head x25_forward_list; 286 + extern rwlock_t x25_forward_list_lock; 300 287 301 288 extern int x25_proc_init(void); 302 289 extern void x25_proc_exit(void);
+1 -1
net/x25/Makefile
··· 6 6 7 7 x25-y := af_x25.o x25_dev.o x25_facilities.o x25_in.o \ 8 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 10 x25-$(CONFIG_SYSCTL) += sysctl_net_x25.o
+25 -5
net/x25/af_x25.c
··· 846 846 struct x25_address source_addr, dest_addr; 847 847 struct x25_facilities facilities; 848 848 struct x25_dte_facilities dte_facilities; 849 - int len, rc; 849 + int len, addr_len, rc; 850 850 851 851 /* 852 852 * Remove the LCI and frame type. ··· 857 857 * Extract the X.25 addresses and convert them to ASCII strings, 858 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 864 * Get the length of the facilities, skip past them for the moment ··· 874 873 sk = x25_find_listener(&source_addr,skb); 875 874 skb_push(skb,len); 876 875 876 + if (sk != NULL && sk_acceptq_is_full(sk)) { 877 + goto out_sock_put; 878 + } 879 + 877 880 /* 878 - * We can't accept the Call Request. 881 + * We dont have any listeners for this incoming call. 882 + * Try forwarding it. 879 883 */ 880 - if (sk == NULL || sk_acceptq_is_full(sk)) 881 - goto out_clear_request; 884 + if (sk == NULL) { 885 + skb_push(skb, addr_len + X25_STD_MIN_LEN); 886 + if (x25_forward_call(&dest_addr, nb, skb, lci) > 0) 887 + { 888 + /* Call was forwarded, dont process it any more */ 889 + kfree_skb(skb); 890 + rc = 1; 891 + goto out; 892 + } else { 893 + /* No listeners, can't forward, clear the call */ 894 + goto out_clear_request; 895 + } 896 + } 882 897 883 898 /* 884 899 * Try to reach a compromise on the requested facilities. ··· 1615 1598 x25_disconnect(s, ENETUNREACH, 0, 0); 1616 1599 1617 1600 write_unlock_bh(&x25_list_lock); 1601 + 1602 + /* Remove any related forwards */ 1603 + x25_clear_forward_by_dev(nb->dev); 1618 1604 } 1619 1605 1620 1606 static int __init x25_init(void)
+11 -2
net/x25/x25_dev.c
··· 67 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. 71 - * Let caller throw it away. 70 + * Its not a Call Request, nor is it a control frame. 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 83 x25_transmit_clear_request(nb, lci, 0x0D); 75 84 */
+163
net/x25/x25_forward.c
··· 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 + }
+3
net/x25/x25_route.c
··· 119 119 __x25_remove_route(rt); 120 120 } 121 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 /*