195a9dc43SAndrew Hendry /* 295a9dc43SAndrew Hendry * This module: 395a9dc43SAndrew Hendry * This module is free software; you can redistribute it and/or 495a9dc43SAndrew Hendry * modify it under the terms of the GNU General Public License 595a9dc43SAndrew Hendry * as published by the Free Software Foundation; either version 695a9dc43SAndrew Hendry * 2 of the License, or (at your option) any later version. 795a9dc43SAndrew Hendry * 895a9dc43SAndrew Hendry * History 995a9dc43SAndrew Hendry * 03-01-2007 Added forwarding for x.25 Andrew Hendry 1095a9dc43SAndrew Hendry */ 1195a9dc43SAndrew Hendry #include <linux/if_arp.h> 1295a9dc43SAndrew Hendry #include <linux/init.h> 1395a9dc43SAndrew Hendry #include <net/x25.h> 1495a9dc43SAndrew Hendry 150e3cf7e9SDenis Cheng LIST_HEAD(x25_forward_list); 1695a9dc43SAndrew Hendry DEFINE_RWLOCK(x25_forward_list_lock); 1795a9dc43SAndrew Hendry 1895a9dc43SAndrew Hendry int x25_forward_call(struct x25_address *dest_addr, struct x25_neigh *from, 1995a9dc43SAndrew Hendry struct sk_buff *skb, int lci) 2095a9dc43SAndrew Hendry { 2195a9dc43SAndrew Hendry struct x25_route *rt; 2295a9dc43SAndrew Hendry struct x25_neigh *neigh_new = NULL; 2395a9dc43SAndrew Hendry struct list_head *entry; 2495a9dc43SAndrew Hendry struct x25_forward *x25_frwd, *new_frwd; 2595a9dc43SAndrew Hendry struct sk_buff *skbn; 2695a9dc43SAndrew Hendry short same_lci = 0; 2795a9dc43SAndrew Hendry int rc = 0; 2895a9dc43SAndrew Hendry 29e4ce837dSAdrian Bunk if ((rt = x25_get_route(dest_addr)) == NULL) 30e4ce837dSAdrian Bunk goto out_no_route; 3195a9dc43SAndrew Hendry 3295a9dc43SAndrew Hendry if ((neigh_new = x25_get_neigh(rt->dev)) == NULL) { 3395a9dc43SAndrew Hendry /* This shouldnt happen, if it occurs somehow 3495a9dc43SAndrew Hendry * do something sensible 3595a9dc43SAndrew Hendry */ 3695a9dc43SAndrew Hendry goto out_put_route; 3795a9dc43SAndrew Hendry } 3895a9dc43SAndrew Hendry 3995a9dc43SAndrew Hendry /* Avoid a loop. This is the normal exit path for a 4095a9dc43SAndrew Hendry * system with only one x.25 iface and default route 4195a9dc43SAndrew Hendry */ 4295a9dc43SAndrew Hendry if (rt->dev == from->dev) { 4395a9dc43SAndrew Hendry goto out_put_nb; 4495a9dc43SAndrew Hendry } 4595a9dc43SAndrew Hendry 4695a9dc43SAndrew Hendry /* Remote end sending a call request on an already 4795a9dc43SAndrew Hendry * established LCI? It shouldnt happen, just in case.. 4895a9dc43SAndrew Hendry */ 4995a9dc43SAndrew Hendry read_lock_bh(&x25_forward_list_lock); 5095a9dc43SAndrew Hendry list_for_each(entry, &x25_forward_list) { 5195a9dc43SAndrew Hendry x25_frwd = list_entry(entry, struct x25_forward, node); 5295a9dc43SAndrew Hendry if (x25_frwd->lci == lci) { 5395a9dc43SAndrew Hendry printk(KERN_WARNING "X.25: call request for lci which is already registered!, transmitting but not registering new pair\n"); 5495a9dc43SAndrew Hendry same_lci = 1; 5595a9dc43SAndrew Hendry } 5695a9dc43SAndrew Hendry } 5795a9dc43SAndrew Hendry read_unlock_bh(&x25_forward_list_lock); 5895a9dc43SAndrew Hendry 5995a9dc43SAndrew Hendry /* Save the forwarding details for future traffic */ 6095a9dc43SAndrew Hendry if (!same_lci){ 6195a9dc43SAndrew Hendry if ((new_frwd = kmalloc(sizeof(struct x25_forward), 6295a9dc43SAndrew Hendry GFP_ATOMIC)) == NULL){ 6395a9dc43SAndrew Hendry rc = -ENOMEM; 6495a9dc43SAndrew Hendry goto out_put_nb; 6595a9dc43SAndrew Hendry } 6695a9dc43SAndrew Hendry new_frwd->lci = lci; 6795a9dc43SAndrew Hendry new_frwd->dev1 = rt->dev; 6895a9dc43SAndrew Hendry new_frwd->dev2 = from->dev; 6995a9dc43SAndrew Hendry write_lock_bh(&x25_forward_list_lock); 7095a9dc43SAndrew Hendry list_add(&new_frwd->node, &x25_forward_list); 7195a9dc43SAndrew Hendry write_unlock_bh(&x25_forward_list_lock); 7295a9dc43SAndrew Hendry } 7395a9dc43SAndrew Hendry 7495a9dc43SAndrew Hendry /* Forward the call request */ 7595a9dc43SAndrew Hendry if ( (skbn = skb_clone(skb, GFP_ATOMIC)) == NULL){ 7695a9dc43SAndrew Hendry goto out_put_nb; 7795a9dc43SAndrew Hendry } 7895a9dc43SAndrew Hendry x25_transmit_link(skbn, neigh_new); 7995a9dc43SAndrew Hendry rc = 1; 8095a9dc43SAndrew Hendry 8195a9dc43SAndrew Hendry 8295a9dc43SAndrew Hendry out_put_nb: 8395a9dc43SAndrew Hendry x25_neigh_put(neigh_new); 8495a9dc43SAndrew Hendry 8595a9dc43SAndrew Hendry out_put_route: 8695a9dc43SAndrew Hendry x25_route_put(rt); 87e4ce837dSAdrian Bunk 88e4ce837dSAdrian Bunk out_no_route: 8995a9dc43SAndrew Hendry return rc; 9095a9dc43SAndrew Hendry } 9195a9dc43SAndrew Hendry 9295a9dc43SAndrew Hendry 9395a9dc43SAndrew Hendry int x25_forward_data(int lci, struct x25_neigh *from, struct sk_buff *skb) { 9495a9dc43SAndrew Hendry 9595a9dc43SAndrew Hendry struct x25_forward *frwd; 9695a9dc43SAndrew Hendry struct list_head *entry; 9795a9dc43SAndrew Hendry struct net_device *peer = NULL; 9895a9dc43SAndrew Hendry struct x25_neigh *nb; 9995a9dc43SAndrew Hendry struct sk_buff *skbn; 10095a9dc43SAndrew Hendry int rc = 0; 10195a9dc43SAndrew Hendry 10295a9dc43SAndrew Hendry read_lock_bh(&x25_forward_list_lock); 10395a9dc43SAndrew Hendry list_for_each(entry, &x25_forward_list) { 10495a9dc43SAndrew Hendry frwd = list_entry(entry, struct x25_forward, node); 10595a9dc43SAndrew Hendry if (frwd->lci == lci) { 10695a9dc43SAndrew Hendry /* The call is established, either side can send */ 10795a9dc43SAndrew Hendry if (from->dev == frwd->dev1) { 10895a9dc43SAndrew Hendry peer = frwd->dev2; 10995a9dc43SAndrew Hendry } else { 11095a9dc43SAndrew Hendry peer = frwd->dev1; 11195a9dc43SAndrew Hendry } 11295a9dc43SAndrew Hendry break; 11395a9dc43SAndrew Hendry } 11495a9dc43SAndrew Hendry } 11595a9dc43SAndrew Hendry read_unlock_bh(&x25_forward_list_lock); 11695a9dc43SAndrew Hendry 11795a9dc43SAndrew Hendry if ( (nb = x25_get_neigh(peer)) == NULL) 11895a9dc43SAndrew Hendry goto out; 11995a9dc43SAndrew Hendry 12095a9dc43SAndrew Hendry if ( (skbn = pskb_copy(skb, GFP_ATOMIC)) == NULL){ 12176975f8aSJulia Lawall goto output; 12295a9dc43SAndrew Hendry 12395a9dc43SAndrew Hendry } 12495a9dc43SAndrew Hendry x25_transmit_link(skbn, nb); 12595a9dc43SAndrew Hendry 12695a9dc43SAndrew Hendry rc = 1; 12776975f8aSJulia Lawall output: 12876975f8aSJulia Lawall x25_neigh_put(nb); 12995a9dc43SAndrew Hendry out: 13095a9dc43SAndrew Hendry return rc; 13195a9dc43SAndrew Hendry } 13295a9dc43SAndrew Hendry 13395a9dc43SAndrew Hendry void x25_clear_forward_by_lci(unsigned int lci) 13495a9dc43SAndrew Hendry { 13595a9dc43SAndrew Hendry struct x25_forward *fwd; 13695a9dc43SAndrew Hendry struct list_head *entry, *tmp; 13795a9dc43SAndrew Hendry 13895a9dc43SAndrew Hendry write_lock_bh(&x25_forward_list_lock); 13995a9dc43SAndrew Hendry 14095a9dc43SAndrew Hendry list_for_each_safe(entry, tmp, &x25_forward_list) { 14195a9dc43SAndrew Hendry fwd = list_entry(entry, struct x25_forward, node); 14295a9dc43SAndrew Hendry if (fwd->lci == lci) { 14395a9dc43SAndrew Hendry list_del(&fwd->node); 14495a9dc43SAndrew Hendry kfree(fwd); 14595a9dc43SAndrew Hendry } 14695a9dc43SAndrew Hendry } 14795a9dc43SAndrew Hendry write_unlock_bh(&x25_forward_list_lock); 14895a9dc43SAndrew Hendry } 14995a9dc43SAndrew Hendry 15095a9dc43SAndrew Hendry 15195a9dc43SAndrew Hendry void x25_clear_forward_by_dev(struct net_device *dev) 15295a9dc43SAndrew Hendry { 15395a9dc43SAndrew Hendry struct x25_forward *fwd; 15495a9dc43SAndrew Hendry struct list_head *entry, *tmp; 15595a9dc43SAndrew Hendry 15695a9dc43SAndrew Hendry write_lock_bh(&x25_forward_list_lock); 15795a9dc43SAndrew Hendry 15895a9dc43SAndrew Hendry list_for_each_safe(entry, tmp, &x25_forward_list) { 15995a9dc43SAndrew Hendry fwd = list_entry(entry, struct x25_forward, node); 16095a9dc43SAndrew Hendry if ((fwd->dev1 == dev) || (fwd->dev2 == dev)){ 16195a9dc43SAndrew Hendry list_del(&fwd->node); 16295a9dc43SAndrew Hendry kfree(fwd); 16395a9dc43SAndrew Hendry } 16495a9dc43SAndrew Hendry } 16595a9dc43SAndrew Hendry write_unlock_bh(&x25_forward_list_lock); 16695a9dc43SAndrew Hendry } 167